2014-10-08 63 views
0

在我的控制器中,我使用ng-click将变量设置为true。

在我的指令中,当变量为真时,我需要评估一些东西。随后,我通过我的指令将变量设置为false。

但是,我的问题是,我似乎无法让$watchng-click函数触发。

我已经包含了我的问题的示例小提琴。如您所见,$watch最初在加载页面时在控制台中记录了true。当我点击指令使其成为false时,$watch也会触发并记录false。然而,随后对ng-click按钮的点击不会导致$watch开火。为什么是这样?

http://jsfiddle.net/zcouyvwc/2/

var app = angular.module('myApp', []); 

function MyCtrl($scope,$timeout) { 

    $scope.boolean = true; 

    $scope.setToTrue = function() { 
     $timeout(function(){$scope.boolean = true;}); 
    }; 
} 


app.directive("someDirective",['$timeout',function($timeout) { 
return { 
    restrict:"A", 
    scope:true, 
    link: function(scope, element, attrs) { 

     scope.$watch("boolean", function() { 
     console.log(scope.boolean); 
     }); 

     element.bind('click',function(){ 
      $timeout(function(){ 
       scope.boolean = false; 
      }); 

     }); 
    } 
} 
}]); 

回答

3

的问题是,someDirective是创建一个子范围,当设置scope.boolean = false,它实际上创建了阴影原来的变量,所以原来的不变

标准咨询,从https://github.com/angular/angular.js/wiki/Understanding-Scopes,是

这个问题与基元可以很容易地避免遵循的“最佳做法”总是有一个'。'在NG的模型

如果你改变你的代码,让你有

$scope.model = { 
    boolean: true 
}; 

http://jsfiddle.net/9j87njvt/1/,那么我认为它会像预期的那样。


作为一个工具,我通常只创建依赖于范围继承这种方式,如果方案比较复杂或者有其他缺点的指令。通常,我通过属性传递选项,并在指令定义中使用scope: {...}作为隔离范围,从而使事情更加分离。另外,我不确定为什么你在几个地方有$timeout。您可能希望使用scope.$apply()以使Angular运行摘要循环以注意模型中的更改。

+0

aaaaahhhhhhhhh我之前有过这个问题,经过几个小时的研究,我纠正了它。我没有意识到它又是同样的问题..... dohh!感谢您注意到这一点! – 2014-10-08 07:11:19

0

你应该知道,boolean是很多(都有)编程语言。作为这样的保留字可以不被用于命名的目的。

Reserved names

首先尝试给另一个有意义的名称,你的变量,然后更新我们,如果它仍然无法正常工作。

0

您是原型范围继承的受害者。你看,指定scope:true意味着该指令创建一个新的范围,该范围原型继承了父范围(控制器的范围)。 (如果您不熟悉概念,请搜索Javascript原型继承。)

休息一下并指定scope:false,表示指令使用父范围。你的小提琴奏效。所以,如果你没有具体的理由要有一个孩子的范围,你就完成了。

如果没有,请继续阅读:与原型范围继承的特点是顶级属性(即$scope.something - 对比$scope.something.deepersomething是顶级水平,deeper是无法)从层次结构中的第一个范围包含这些阅读,但总是写入当前范围。在开始的时候,范围层次是:

controller scope (contains "boolean" top level prop, value: true) 
| 
+- directive child scope (contains nothing) 

一下情况后变为:

controller scope (contains "boolean" top level prop, value: true) 
| 
+- directive child scope (contains "boolean" top level prop, value: false) 

手表被放置在指令范围,因此读取子范围boolean财产;在这种情况下,它始终是false,手表从不触发。

答案是使用非顶级属性。将boolean对象下的控制范围,即$scope.data.boolean = true相若方式和适应的指令:

scope.$watch("data.boolean", function() { ... }); 

element.bind('click',function(){ 
    scope.$apply(function() { 
     scope.data.boolean = false; 
    ... 

当你在它,给boolean一个更好的名字! (请参阅developer10的回答)

并使用$scope.$apply而不是$timeout