$scope of one controller effects binding of 2nd controller

51 views
Skip to first unread message

mr emmech

unread,
Apr 1, 2015, 11:46:36 PM4/1/15
to ang...@googlegroups.com
I'm trying to convert an application from pure JS to AngularJS and have run into a problem that I've extracted into the following code snipet.

I have two controllers that each call an SSE server and each has its own callback function. My understanding is that $scope for each controller would be different and modifying one would not effect the other.

However, whenever eventBCallBack() in eventBCtrl is executed, it seems to effect $scope of eventACtrl. My filter which is being called in eventACtrl is executed whenever eventBCallBack() is executed. Even if eventBCallBack() is an empty function, it makes no difference.

I suspect it has something to do with $scope.$apply.

Following is the HTML file:

    <!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/test.js"></script>
   
</body>
   
</html>



Following is the javascript code:

    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;
     
};
   
});



Anurag Sharma

unread,
Apr 2, 2015, 1:19:37 AM4/2/15
to ang...@googlegroups.com
Hi,

I guess it is not a problem of $scope.$apply, I am not quite sure why it is happening. May be because two SSE events are invoked inside a single page.

However, we can use single SSE call(EVENTS:A) rather than using two different calls. We can attach results of (EVENTS:B) into (EVENTS:A) itself and parse it as a JSON to use it as "cpu".

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

        
};

Using above scenario, there will be no conflicts as there is only single event callback.

Also, there no need of using scope.apply, because controller is already having digest cycle. So scope.apply will be already in running within the controller.

Please do let me know if that helps out.

Thank you,
Anurag.

Sander Elias

unread,
Apr 2, 2015, 1:49:51 AM4/2/15
to ang...@googlegroups.com

Hi,

You are right. This is because of $scope.$apply That’s the reason you should use it as sparingly as possible. an $apply will make sure that every watch in your application is fired at least once. The reason is, that in your eventBCallback you might have changed something that otherwise might get unnoticed, (lets assume you add a new module to the modules array (yeah I know that isn't easy possible,but angular does not!)) and therefore the filters need too be fired also.

If you are really sure that what you are doing in your evenBCallback does not affect other places, but indeed only the local scope, you can sue $scope.$digest() in stead of $scope.$apply, but you better be sure you know what you are doing!

Regards
Sander

hingorjo mr

unread,
Apr 2, 2015, 9:35:30 AM4/2/15
to ang...@googlegroups.com
Thanks. I actually need multiple event handlers because some events are executed at a very high frequency and are used in canvas animations. I can't afford to have every watch in the application fired on such callbacks.

Initially I was using a single controller and changed to multiple controllers to isolate the scope of each controller and its event handlers.

--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/FCyO0IMU-g0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.

hingorjo mr

unread,
Apr 2, 2015, 9:39:05 AM4/2/15
to ang...@googlegroups.com
Thanks. But I was under the assumption that each controller will have a separate scope. I'm not using nested controllers. If this is a valid assumption, then why should modifying the scope of one controller effect the other?

--

hingorjo mr

unread,
Apr 2, 2015, 9:40:23 AM4/2/15
to ang...@googlegroups.com
Furthermore, I am using scope.apply because otherwise the callback function did not trigger any watch.

On Thu, Apr 2, 2015 at 1:19 AM, Anurag Sharma <asaar...@gmail.com> wrote:

--

Tandon, Rishi

unread,
Apr 2, 2015, 9:44:24 AM4/2/15
to ang...@googlegroups.com
 why should modifying the scope of one controller effect the other?

To avoid that, use ISOLATED scope, 

--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.

To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.



--
Rishi Tandon
Pearson Learning Technology Group

Mobile: (310) 926-9032

Pearson
Always Learning
Learn more at www.pearson.com

hingorjo mr

unread,
Apr 2, 2015, 8:06:24 PM4/2/15
to ang...@googlegroups.com
I've worked out the solution.

The problem was that $apply works at root scope so it is not limited to the scope of a particular controller.

The solution I came up with was to remove $scope from the callback function and within the callback function call $digest. This way, $digest is limited to the scope of the current controller and does not trigger the watchers for any other scope.

Sander Elias

unread,
Apr 3, 2015, 5:23:02 AM4/3/15
to ang...@googlegroups.com
Thanks. But I was under the assumption that each controller will have a separate scope. I'm not using nested controllers.
This is correct, each controller has its own scope. Both inherit from $rootScope.

 
If this is a valid assumption, then why should modifying the scope of one controller effect the other?
In your case, it does not. However the point is that angular can't guarantee this. So if you do something outside it's scope, and you call $apply, all watchers fire. This needs to be done, to make sure that everything is in sync. Hence by advice to you to utilize $digest in your case. 

Regards
Sander
Reply all
Reply to author
Forward
0 new messages