2014-02-09 54 views
23

我目前正在玩一個角度的應用程序,它使用websocket與後端進行通信。我有一些麻煩,讓角度的數據綁定正常工作。

在下面的例子中,我創建了一個創建websocket連接的服務。如果websocket收到消息,我只是將該消息推送到包含所有收到消息的數組中。

在我的控制器中,我將該消息數組綁定到示波器,然後使用ng-repeat將它們全部列在我的局部視圖中。

服務:

factory('MyService', [function() { 

    var wsUrl = angular.element(document.querySelector('#ws-url')).val(); 
    var ws = new WebSocket(wsUrl); 

    ws.onopen = function() { 
    console.log("connection established ..."); 
    } 
    ws.onmessage = function(event) { 
     Service.messages.push(event.data); 
    } 

    var Service = {}; 
    Service.messages = []; 
    return Service; 
}]); 

控制器:

controller('MyCtrl1', ['$scope', 'MyService', function($scope, MyService) { 
    $scope.messages = MyService.messages; 
}]) 

部分:

<ul> 
    <li ng-repeat="msg in messages"> 
     {{msg}} 
    </li> 
</ul> 

然而,這無法正常工作。當收到新消息並將其推入數組中時,應顯示所有消息的列表不會更新。我預計它會因爲角度雙向數據綁定而更新。

我發現一個解決方案,通過包裝的消息推到一個呼叫服務工程$rootScope.apply()

ws.onmessage = function(event) { 
    $rootScope.$apply(function() { 
    Service.messages.push(event.data); 
    }); 
} 

我的問題是:

  1. 這是預期角度的行爲,如果我不使用$rootScope.apply(),我的列表不會自動更新?

  2. 爲什麼我甚至需要把它包裝在$rootScope.apply()

  3. 正在使用$rootScope.apply()正確的方法來解決這個問題?

  4. 對於這個問題,$rootScope.apply()有更好的選擇嗎?

回答

31
  1. 是的,AngularJS的綁定 「回合制」,他們只對某些DOM事件和調用$apply/$digest火災。有一些有用的服務,如$http$timeout可爲您打包,但anything outside of that requires calls to either $apply or $digest

  2. 您需要讓AngularJS知道您已經更改了綁定到範圍的變量,以便它可以更新視圖。還有其他方法可以做到這一點。

  3. 這取決於你需要什麼。當您的代碼包裝在$apply()中時,AngularJS將您的代碼封裝在內部的angularjs日誌記錄和異常處理中,當它結束時,它會將$digest傳播到您的控制器的所有範圍。在大多數情況下,包裝在$apply()是最好的方式,它留下更多的門打開將來可能最終使用的角度的未來功能。這是正確的方式嗎?參見下文。

  4. 如果您不使用Angular的錯誤處理,並且您知道您的更改不應該傳播到任何其他作用域(根目錄,控制器或指令),並且需要針對性能進行優化,則可以專門撥打$digest你的控制器的$scope。這樣,髒檢查不會傳播。否則,如果您不希望錯誤被Angular捕獲,但需要將髒檢查傳播到其他控制器/指令/ rootScope,則可以在完成更改後調用$rootScope.$apply()而不是打包$ apply

更多參考: $apply vs $digest

+0

所以,你說的任何東西'$ timeout'包裹,會自動應用正確的? – aacanakin

+1

是@aacanakin $ timeout的回調函數中的任何同步代碼都會自動應用。 – Juliano