Reputation: 1496
How to handle events (like $rootScope
or socket events) in an Angular controller correctly? I'm facing the problem that my controllers aren't destroyed, which cause some problems when it comes to listening to specific events.
To make it clear what I mean here's a plunker: http://plnkr.co/edit/CkXKUnpUdsbnZEjq8zLy?p=preview
Triggering the rootscope event (by clicking on the button) in the first place works as intended: just one event is fetched. But navigating to Route 2
and triggering the rootscope event again shows my problem; the event is fetched twice, since (at least that's my guess) both controllers are active now. Every route switch causes an additional event listener.
How to handle this?
Upvotes: 0
Views: 350
Reputation: 249
The answer given by JosselinTD is correct. If an event is broadcasted on the $rootScope it is sufficient to listen on your respective controller's $scope as a broadcast is triggered on all scopes that are hierarchically below the scope that the event is triggered on and all other scopes reside somewhere below the $rootScope.
If this is not an option, e.g. because you want to catch an event that is emitted (using the $emit method instead of $broadcast) and does not pass your $scope, you can actually listen on the $rootScope as well. In that case you MUST make sure, though, that the listener cleaned up when your controller's scope is destroyed:
var removeListener = $rootScope.$on('yourEvent', function(event) {
// do what you want here..
});
// remove the listener on $rootScope when $scope is cleaned up
// this makes sure we have no unwanted references..
$scope.$on('$destroy', removeListener);
The $on method returns a function which allows to remove the listener created by it. AngularJS will call the $destroy event on your $scope when a controller is destroyed (e.g. because its view is replaced by something else).
If you are listening to non-angular-events in a controller you should also use a
$scope.$on('$destroy', function() {
//TODO: call some clean-up function to remove your event listener
});
It might be a listener removal as described in socket io listener removal (stackoverflow)
Another hint that may be useful: In case you are listening to events coming from outside of your AngularJS context (which applies to e.g. DOM events, but certainly also to socket.io events) you will have to wrap them in a $scope.$apply as AngularJS will otherwise be unaware of any changes brought by the event listener.
socket.on('someSocketEvent', function(data) {
$scope.$apply(function() {
$scope.dataFromSocket = data;
});
});
Upvotes: 1
Reputation: 621
Use $scope.$on
instead of $rootScope.$on
, the listeners will be destroyed on scope destruction automatically.
Upvotes: 1