[英]$watch does not fire in directive
在我的控制器中,我使用ng-click
將變量設置為true。
在我的指令中,當變量為true時,我需要評估某些內容。 隨后,我通過指令將變量設置為false。
但是我的問題是我似乎無法從ng-click
函數中觸發$watch
。
我提供了一個有關問題的樣本。 如您所見, $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;
});
});
}
}
}]);
問題是someDirective
正在創建一個子范圍,並且當它設置scope.boolean = false
,它實際上創建了一個變量,該變量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運行摘要循環來注意到模型中的更改。
您是原型作用域繼承的受害者。 您會看到,指定scope:true
意味着指令創建了一個新的范圍,該范圍典型地繼承了父范圍(控制器的范圍)。 (如果您不熟悉Javascript原型繼承,則進行搜索。)
稍作休息,然后指定scope:false
,這意味着該指令使用父范圍。 你的小提琴奏效。 因此,如果您沒有特定的理由擁有子范圍,那么您就完成了。
如果沒有,請繼續閱讀:與原型范圍繼承的特點是頂級屬性(即$scope.something
-相比於$scope.something.deeper
→ something
是頂級水平, 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
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.