2015-04-02 80 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

相关问题