1

更新值時,$ rootScope上的Angularjs $ watchCollection不會觸發我遇到了一些問題,解決了我正在使用的一些Angularjs功能的問題。當從指令

基本的想法是,我有一個系統,在允許用戶前進到應用程序的下一部分之前必須符合某些標準。其中一個例子是,用戶必須同時添加評論,並點擊鏈接(在真實應用中,這是一個文件下載),以便他們前進。

您可以在這裏完整的例子來看看:https://jsfiddle.net/d81xxweu/10/

我會假設HTML是非常自我解釋,並移動到什麼,我用我的角模塊做。我的應用程序聲明和初始化如下:

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

myApp.run(function ($rootScope) { 
    // Both of these must be met in order for the user to proceed with 'special-button' 
    $rootScope.criteria = { 
     criteria1: false, 
     criteria2: false 
    }; 
}); 

這很簡單。我將一個名爲criteria的對象附加到應用程序的根作用域,以使其可以被我的指令和控制器訪問。我有一個指令,用於呈現允許用戶在符合條件時前進的鏈接。在這個例子中,鏈接的文本從「正在等待......」改爲「點擊繼續」,以表明我們可能會前進。

myApp.directive('specialButton', function ($rootScope) { 
    return { 
     scope: true, 
     template: "<a href='#'>{{ linkText }}</a>", 
     replace: true, 
     link: function (scope, el, attrs) { 
      scope.linkText = 'Waiting...'; 

      var setLinkState = function(currentCriteria) { 
       var criteriaMet = true; 

       for(var k in $rootScope.criteria) { 
        if($rootScope.criteria[k] == false) { 
         criteriaMet = false; 
        } 
       } 

       if(criteriaMet) { 
        scope.linkText = 'Click to proceed'; 
       } 
      }; 

      // Watch for changes to this object at the root scope level 
      $rootScope.$watchCollection('criteria', function(newValues) { 
       setLinkState(newValues); 
      }); 
     } 
    }; 
}); 

所以爲了引發我們對這個指令設置表的語句,我可以添加評論所允許的該控制器:

myApp.controller('comments', function ($scope, $rootScope) { 
    $scope.commentText = ''; 
    $scope.comments = []; 

    $scope.addComment = function() { 
     $scope.comments.push({ commentText: $scope.commentText }); 
     $scope.commentText = '' 

     // When the user adds a comment they have met the first criteria 
     $rootScope.criteria.criteria1 = true; 
    }; 
}); 

以前是我的顯示/添加註釋控制器。我在此處將criteria1設置爲true以指示用戶添加了評論。這實際上可以正常工作,並且specialButton指令中的$ watchCollection按預期調用。

當我嘗試從必須點擊的鏈接執行相同的操作以提前時出現問題。這是用一個指令來呈現的,因爲據我的理解,在這種情況下,與註釋列表/表單不同,指令比控制器更有意義。

myApp.directive('requiredLink', function($rootScope) { 
    return { 
     scope: true, 
     template: "<a href='#'>Click me!</a>", 
     replace: true, 
     link: function(scope, el, attrs) { 
      el.bind('click', function(evt) { 
       evt.preventDefault(); 

       // When the user clicks this link they have met the second criteria 
       $rootScope.criteria.criteria2 = true; 
      }); 
     } 
    }; 
}); 

正如你在這裏看到的,我在$ rootScope中傳遞,就像在控制器中一樣。但是,當我將criteria2設置爲true時,$ watchCollection不會被觸發。

那麼最終發生的是如果我先添加註釋,然後單擊其他按鈕,我沒有看到specialButton更新其文本,因爲第二次更改從不觸發手錶。但是,如果我先點擊鏈接,然後添加一條評論,按照預期更新specialButton。 requiredLink的點擊是更新數據,但不觸發手錶。因此,當我添加註釋並觸發$ watch時,會看到BOTH已設置爲true。

在此先感謝您爲解決此問題提供的任何幫助;我感謝你的時間。

回答

1

你的實際問題是你正在更新$rootScope從角度上下文以外的事件,所以它明顯的角度綁定不會更新,因爲在這種情況下消化週期不會被解僱。你需要使用的$rootScope

el.bind('click', function(evt) { 
    evt.preventDefault(); 
    // When the user clicks this link they have met the second criteria 
    $rootScope.criteria.criteria2 = true; 
    $rootScope.$apply(); //this will run digest cycle & will fire `watchCollection` `$watcher` 
}); 

Demo Plunkr

雖然這個解決方案工作$apply()方法手動啓動它,但我會建議你使用使用$rootScope

代替 服務對於使用服務的實現,您需要遵循以下對您有幫助的事情。

您的服務應該使用criteria變量對象的形式,應該遵循dot rule,這樣每當你想使用它的相應的參考將更新使用JavaScript原型

SEVICE

app.service('dataService', function(){ 
    this.criteria = { 
     criteria1: false, 
     criteria2: false 
    }; 
    //...here would be other sharable data. 
}) 

你需要在控制器,指令,過濾器的任何地方注入它。

雖然從指令看守服務變量,你需要做下面的事情。

指令

myApp.directive('specialButton', function (dataService) { 
    return { 
     scope: true, 
     template: "<a href='#'>{{ linkText }}</a>", 
     replace: true, 
     link: function (scope, el, attrs) { 
      //.. other code 

      // deep watch will watch on whole object making last param true 
      scope.$watch(function(){ 
       return dataService.criteria //this will get get evaluated on criteria change 
      }, function(newValues) { 
       setLinkState(newValues); 
      }, true); 
     } 
    }; 
}); 
+0

謝謝,這樣可以解決問題。我想過使用服務,但問題是我需要能夠從我的specialButton指令外部觀察數據以進行更改。我該如何設法觀看服務數據? – slave2zeros

+0

@ slave2zeros讓我更新我的答案..這也會幫助你.. –

+0

@ slave2zeros看看我的更新答案.. \ –