簡體   English   中英

$ watch不會在指令中觸發

[英]$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.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

您應該意識到, boolean是許多(所有)編程語言中的保留字,因此可能不會用於命名目的。

保留名稱

首先嘗試給您的變量賦予另一個有意義的名稱,然后在變量仍然無效的情況下更新我們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM