在我的控制器中,我使用ng-click
将变量设置为true。
在我的指令中,我需要在变量为true时评估某些内容。随后,我通过我的指令将变量设置为false。
但是我的问题是我似乎无法从$watch
函数触发ng-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;
});
});
}
}
}]);
答案 0 :(得分: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运行摘要周期以注意模型中的更改。
答案 1 :(得分:1)
您是原型范围继承的受害者。您可以看到,指定scope:true
意味着该指令创建了一个新的作用域,该作用域原型继承了父作用域(控制器的作用域)。 (如果您不熟悉这个概念,请搜索Javascript原型继承。)
稍作休息并指定scope:false
,这意味着该指令使用父作用域。你的小提琴有效。因此,如果您没有特定的理由拥有子范围,那么您就完成了。
如果没有,请继续阅读:原型范围继承的特征是顶级属性(即$scope.something
- 与$scope.something.deeper
→something
相比是顶级属性{{1}从包含它们的层次结构中的第一个范围读取,但始终写入当前范围。最初,范围层次结构为:
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;
...
一个更好的名字! (见developer10的回答)
并使用上面的boolean
代替$scope.$apply
。
答案 2 :(得分:0)