2015-06-20 69 views
4

说我们有这个表达式AngularJS看着表达

$scope.showButton = users.is_admin() && !document.is_provided; 

然后在相同的控制器,你有一个按钮,更新的Document.is_provided值:

<button ng-click="document.is_provided = true;">Provide document</button> 

的问题是,$scope.showButton现在应该改变了,但并没有改变。

更新时间: Plnkr显示简单的问题:http://plnkr.co/edit/Qk2jnHAmqsrNXSAjDYEk?p=preview

+0

回答更新。 – outoftime

+0

为什么你认为'$ scope.showButton'的值应该改变? – zeroflagL

+0

我需要一种方法来重新计算..所以我要求最好的方法来做到这一点使用角度(而不是包装它的功能,然后调用它,每次我改变它的值) –

回答

4

我想添加到squiroid的回答,为什么给你解释作品。我会提供一个非常简单的方法让你理解,因为这对我来说也是一个非常普遍的问题,当我开始时。

Angular有一些东西叫Digest循环。它是连续调用的一系列函数,以确保如果变量A与另一个变量B双向绑定(例如使用ng-model),它们总是保持同步(即始终具有相同的值)。角度提供的函数(或服务,通常以$开头,如$ timeout等)自动启动摘要循环

因此,假设您有一个变量A并且已将它绑定到$ scope变量B ,它等于一个变量C.你会期望C也被绑定到A,对吧?因为你认为当你改变C时,B应该改变,所以A也应该改变。但是这只有在你开始摘要循环时才有可能。循环将查找需要更新的变量,并将更新它们。然而,通过简单地改变C的值,你永远不会触发摘要循环,所以你的改变永远不会传播到A.

当你在$ watch中放置一个变量时你会做什么(如$建议) ,你会强制开始一个摘要循环。所以现在当你改变C时,你开始了这个循环,它追踪到它需要更新A,这就是它工作的原因。

在你的例子中,$ scope.showButton被绑定到document.is_provided。现在,您正在使用非角度函数来更改document.is_provided的值。这意味着您不会触发摘要循环,这意味着您的更改永远不会传播到$ scope.showButton。因此,showButton始终保持为假。

和当然,一个例子来帮助你理解: http://jsbin.com/vojoso/edit?js,console,output

看控制台。我已经添加了日志来帮助你理解。 注释$ watch语句,看看会发生什么。 试着理解它,然后自己做,你会得到它。

希望我帮助:)

+0

非常感谢!实际上我不明白的是他们如何能够在没有$ watch的情况下工作......并使用var main = this; 有什么想法? –

+0

我不确定。我认为他们以某种方式保存了控制器的状态?我不得不说,我不认为我见过这种代码。抱歉。 :/ – madebysid

3

我不知道,但你可以在上面看: -

$scope.$watch(function(){ 
    return Users.is_admin() && !Document.is_provided; 
},fuction(newVal){ 
$scope.showButton =newVal; 
}); 

希望它能帮助:)

+0

这也适用!但我更愿意看看我们如何才能使它工作,而不需要$ watch –

+0

我不明白这一点。这里正在观看的是什么?介意解释一下? – geckob

+1

@geckob如果返回值为true(这意味着Users.is_admin()和!Document.is_provided都是true),则第一个参数是应该被监视的表达式(在这种情况下,它是一个返回true或false的函数) )$ scope.showButton变为true。所以Angular监督Users.is_admin()和Document.is_provided这两个“值得关注”的值。通常情况下,你只需要一个值,例如$ scope。$ watch('scopesVariable',function(newVal,oldVal){...}),但是通常也可以定义一个函数,参见https:// docs。 angularjs.org/api/ng/type/$rootScope.Scope – ilmgb

2

这里是关于好文章$scope.$watch,它应该有助于了解如何解决您的问题。

它需要更大的答案添加代码,这将解释Document变量和您的REST服务。

UPD:我看到你改变了你原来的问题。我想你对控制器有麻烦。尽量不要使用$scope含蓄,使用data属性为悲伤angular code style

还显示了部分在你模板,你连接控制器。

UPD 2:你的我的话有些误会,所以我修改了plunker example

的index.html

<html ng-app="plunker"> 
    <body ng-controller="MainController as main"> 

    <div ng-show="main.data.document.is_provided">visible</div> 
    <button ng-click="main.hide()">Hide</button> 

    <script data-require="angular[email protected]" 
      src="https://code.angularjs.org/1.4.1/angular.js" 
      data-semver="1.4.1"></script> 
    <script src="app.js"></script> 
    </body> 
</html> 

app.js

angular 
    .module('plunker', []) 
    .controller('MainController', MainController); 

function MainController() { 
    var main = this; 

    this.data = { 
     document: { 
     is_provided: true 
     } 
    }; 

    this.hide = hide; 

    function hide() { 
     main.data.document.is_provided = false; 
    } 
} 

你有一个问题在里面ng-click,因为应该有功能执行。此外,您正在使用ng-if而不是ng-show

+0

谢谢你的帮助。我创建了一个工作plnkr向您显示问题: http://plnkr.co/edit/Qk2jnHAmqsrNXSAjDYEk?p=preview –

+0

OP显式使用'$ scope'。你的意思是什么'data'属性? – zeroflagL

+0

我在他提到它之后加了他们 –

2

最好的方法(imho)来处理这种问题: 在您的看法中使用{{ anyObject | json }}

这样你就知道你正在使用的引用和对象是否在你的范围内。使用| json可以在您的对象存在但空时为您提供赞誉{}。如果您的物体不在您的示波器中,请注意已“印制”。

在你的情况,身体标记更改为: <body ng-controller="MainCtrl as mainCtrl">

然后,这个控制器添加的HTML中:

DATA: {{mainCtrl | json}} 

所以,现在你看到你的变数!而且你也看到点击按钮不会改变布尔变量。

一些额外的调试和重写,这个工程:

app.controller('MainCtrl', function($scope) { 

var main = this; 

this.data = { 
    document: { 
    is_provided: true 
    } 
}; 



$scope.hide = function() { 
    console.log(main); 
    main.data.document.is_provided = !main.data.document.is_provided; 
} 
}); 

和: <button ng-click="hide()">Hide</button>(注意括号)

+1

请注意,如果您将它包装在'pre'标签中:'

{{ data | json }}
',那么您可以通过该调试技巧获得更好的可读性。 – JcT

+0

@Sander_P谢谢你的回答,但我仍然不明白你为什么使用'var main = this'有没有一篇文章可以指导我完成这个任务?我现在明白它是如何工作的,但我从未见过它。 –

+0

这是在我的代码中的原因是因为它在你的代码:)我个人尽量避免在我的控制器中尽可能使用代码,并把它放在指令(DOM逻辑)或服务(业务逻辑)。尝试使用带有** link **函数的指令,并使用$ scope而不是“this”。 –