2015-04-02 81 views
1

我試圖將應用程序從純JS轉換爲AngularJS,並且遇到了一個問題,我已經提取到下面的代碼snipet中。angularJS在一個控制器中的http回調函數修改其他控制器的範圍

我有兩個控制器,每個調用一個SSE服務器,每個都有自己的回調函數。我的理解是每個控制器的$範圍是不同的,修改一個不會影響另一個。

但是,只要eventBCtrl中的eventBCallBack()被執行,它就會影響eventACtrl的$ scope。我在eventACtrl中調用的過濾器在執行eventBCallBack()時執行。即使eventBCallBack()是一個空函數,也沒有區別。

我懷疑它與$ scope。$ apply有關。

以下是HTML文件:

<!DOCTYPE html> 
<html ng-app="testApp"> 
<body> 
    <div ng-controller="eventACtrl"> 
    <div>{{day}}</div> 
    <lable for="filteredName">Filter:</label> 
    <input type="text" name="filteredName" ng-model="filteredName"/> 
    <table> 
    <tbody> 
     <tr ng-repeat="module in modules | matchFilter:filteredName | orderBy: 'name'"> 
      <td>{{$index+1}}</td> 
      <td>{{module.name}}</td> 
     </tr> 
    </tbody> 
    </table> 
    </div> 
    <div ng-controller="eventBCtrl"> 
    {{cpu}} 
    </div> 
    <script src="js/angular.min.js"></script> 
    <script src="js/chaos.js"></script> 
</body> 
</html> 

以下是JavaScript代碼:

var testApp = angular.module("testApp", []); 
testApp.controller("eventACtrl", function($scope) { 

    var eventACallback = function(e) { 
     $scope.$apply(function() { 
     var pData = JSON.parse(e.data); 
     var sDate = new Date(Number(pData.date)); 
     $scope.day = sDate.toDateString() + " " + sDate.toLocaleTimeString(); 
     $scope.modules = pData.modules; 
     console.log("EVENTA"); 
     }); 
    } 

    var source = new EventSource("http://" + location.host +"/EVENTS:A"); 
    source.addEventListener("EVENTA", eventACallback, false); 
}); 

testApp.controller("eventBCtrl", function($scope) { 

    var eventBCallback = function(e) { 
     $scope.$apply(function() { 
      var pData = JSON.parse(e.data); 
      $scope.cpu = pData.cpu; 
      console.log("EVENTB"); 
     });  
    } 

    var source = new EventSource("http://" + location.host + "/EVENTS:B"); 
    source.addEventListener("EVENTB", eventBCallback, false); 
}); 


testApp.filter("matchFilter", function() { 
    return function(modules, filteredName) { 
     console.log("filter: " + filteredName); 
     var newModules = []; 
     for (var i in modules) { 
      if (modules[i].name.search(filteredName) != -1) { 
       newModules.push(modules[i]); 
      } else 
       continue; 
     } 
     return newModules; 
    }; 
}); 
+0

爲什麼不使用單個連接的事件而不是兩個連接,例如活動,通過http://location.host/event?'EVENTA'和'EVENTB'? – 2015-04-02 14:30:20

+0

其中一個事件以高頻率重複(每秒10到100次)。另一個事件並不多,但更新了一個非常非常大的表格。每當高頻事件發生時,我都無法承受大桌面事件的發生。無論如何,我現在已經明白了問題的根源。 $ scope。$ apply並不侷限於控制器的範圍。它在根範圍內運作。我想我需要一些如何調用$摘要而不是$ apply來限制某個控制器的範圍。問題是,$ digest目前似乎沒有工作! – 2015-04-02 22:38:06

+0

看來,這是因爲你的服務器邏輯。雖然,考慮到[瀏覽器限制同時連接的數量],這是不期望的(但並不重要)(http://stackoverflow.com/questions/985431/max-parallel-http-connections-in-a-browser)。 – 2015-04-03 04:04:52

回答

0

從你所描述的,控制器A具有以任何方式不是「修改」的範圍, 對?沒有分配到範圍的新模型或這些模型的值發生更改。

所發生的一切就是您的過濾器被執行。這是可以預料的 - 無論摘要是如何啓動的,在每個摘要循環中都會執行數組過濾器。

下面就來重現您的問題沒有任何控制器或異步功能與$scope.$apply較小的方式(ng-if創建一個新的子範圍)

<div ng-if="true" ng-init="items = [1, 2, 3]> 
    <div ng-repeat="item in items | doNothing">{{item}}</div> 
</div> 
<button ng-click="">clicking me triggers digest</button> 

doNothing這裏是:

.filter("doNothing", function(){ 
    return function(arr){ 
    console.log(arr); 
    return arr; 
    } 
}); 
+0

感謝您的反饋。 – 2015-04-02 11:45:58

+0

所以在我介紹的代碼中,什麼時候可以正常執行摘要循環?似乎每次執行異步函數時都會調用該過濾器。我的異步函數可能每秒執行多次,每次調用過濾器。如果未執行異步功能,則從不調用過濾器(除了最初)。 – 2015-04-02 11:50:40

+0

@mremmech,當調用'$ scope。$ digest'時執行摘要循環。通常,這是由Angular在內部完成的(象ng-click這樣的指令),或者用'$ q'處理異步函數,或者內置Angular服務,比如'$ http'和'$ timeout'。當你手動處理一個異步函數時,'$ scope。$ apply'從根調用一個摘要。過濾器功能以及任何$監視的表達式都會在每個摘要上重新評估。 – 2015-04-02 13:36:18

-1

在這裏張貼問題並在其他論壇上真的很有幫助。我現在清楚瞭解這個問題並制定瞭解決方案。

首先,$ scope。$ apply適用於根作用域。這意味着即使我有單獨的控制器,$ apply也會觸發所有$ scope對象的監視器,而不僅僅是調用$ apply被調用的控制器。

解決方案是從回調函數中移除$ scope,並從函數內調用$ digest。這樣,$摘要只會影響當前範圍。

如下:

testApp.controller("eventBCtrl", function($scope) { 

    eventBCallback = function(e) { 
      var pData = JSON.parse(e.data); 
      $scope.cpu = pData.cpu; 
      $scope.$digest(); 
      console.log("EVENTB"); 
    } 

心中已經測試了這一點,它工作正常。

+0

這會有所幫助,但這不是「解決方案」。包括不相關的'ng-click'或其他應用程序中的任何內容都會觸發摘要循環,並會導致您的過濾器函數運行。解決它的方法是在控制器中進行預過濾 - 而不是在視圖中。 – 2015-04-06 01:10:47

相關問題