Listen for multiple events on a $scope
Solution 1
Yes. Like this:
app.directive('multipleSadness', function() {
return {
restrict: 'C',
link: function(scope, elem, attrs) {
function sameFunction(eventId) {
console.log('Event: ' + eventId + '. The Ferrari is to a Mini what AngularJS is to ... other JavaScript frameworks.');
}
scope.$on('event:auth-loginRequired', function() {sameFunction('auth-loginRequired');});
scope.$on('event:auth-loginConfirmed', function () {sameFunction('auth-loginConfirmed');});
}
};
});
But just because you can, doesn't mean you should :). If the events are continue to propagate up to another listener and they are handled differently there, then maybe there is a case to do this. If this is going to be the only listener than you should just emit (or broadcast) the same event.
Solution 2
The other answers (Anders Ekdahl) are 100% correct... pick one of those... BUT...
Barring that, you could always roll your own:
// a hack to extend the $rootScope
app.run(function($rootScope) {
$rootScope.$onMany = function(events, fn) {
for(var i = 0; i < events.length; i++) {
this.$on(events[i], fn);
}
}
});
app.directive('multipleSadness', function() {
return {
restrict: 'C',
link: function(scope, elem, attrs) {
scope.$onMany(['event:auth-loginRequired', 'event:auth-loginSuccessful'], function() {
console.log('The Ferrari is to a Mini what AngularJS is to ... other JavaScript frameworks');
});
}
};
});
I suppose if you really wanted to do the .split(',')
you could, but that's an implementation detail.
Solution 3
AngularJS does not support multiple event binding but you can do something like this:
var handler = function () { ... }
angular.forEach("event:auth-loginRequired event:auth-loginConfirmed".split(" "), function (event) {
scope.$on(event, handler);
});
Solution 4
I don't think that's possible, since the event might send data to the callback, and if you listen to multiple events you wouldn't know which data came from which event.
I would have done something like this:
function listener() {
console.log('event fired');
}
scope.$on('event:auth-loginRequired', listener);
scope.$on('event:auth-loginConfirmed', listener);
Solution 5
Also like with $rootScope.$onMany (solution from @ben-lesh) it's possible to extend $on method:
var $onOrigin = $rootScope.$on;
$rootScope.$on = function(names, listener) {
var self = this;
if (!angular.isArray(names)) {
names = [names];
}
names.forEach(function(name) {
$onOrigin.call(self, name, listener);
});
};
took from here.
Comments
-
Michael Robinson about 4 years
I have a directive that binds some functions to the local scope with
$scope.$on
.Is it possible to bind the same function to multiple events in one call?
Ideally I'd be able to do something like this:
app.directive('multipleSadness', function() { return { restrict: 'C', link: function(scope, elem, attrs) { scope.$on('event:auth-loginRequired event:auth-loginSuccessful', function() { console.log('The Ferrari is to a Mini what AngularJS is to ... other JavaScript frameworks'); }); } }; });
But this doesn't work. The same example with the comma-separated event name string replaced with
['event:auth-loginRequired', 'event:auth-loginConfirmed']
doesn't wrk either.What does work is this:
app.directive('multipleSadness', function() { return { restrict: 'C', link: function(scope, elem, attrs) { scope.$on('event:auth-loginRequired', function() { console.log('The Ferrari is to a Mini what AngularJS is to ... other JavaScript frameworks'); }); scope.$on('event:auth-loginConfirmed', function() { console.log('The Ferrari is to a Mini what AngularJS is to ... other JavaScript frameworks'); }); } }; });
But this is not ideal.
Is it possible to bind multiple events to the same function in one go?
-
Ryan O'Neill over 11 yearsIs there a reason why you would use "event:auth-loginRequired event:auth-loginConfirmed".split(" ") instead of just ['event:auth-loginRequired', 'event:auth-loginConfirmed']?
-
bmleite over 11 years@RyanO'Neill No special reason =) It just seems more neat having a single string than having ['','','',...]. Also OP's example was with a single string separated by commas.
-
Ryan O'Neill over 11 yearsThanks. JavaScript being what it is, just wanted to make sure I wasn't missing a Wat moment that I should know about.
-
Michael Robinson over 11 yearsThanks for the extra information regarding event propagation & event ID's, knowing this I understand why what I ask isn't natively possible. The events do have different listeners, this one listener needs to perform the same action on multiple events however.
-
Michael Robinson over 11 yearsAfter consideration I have refactored my code to be more Angular. There are still two events, but as they signify different things (in the refactoring), there is no reason to bind them both to the same function. Thanks for the pointers.
-
testing123 over 11 yearsNo problem at all. Glad I could help.
-
Michael J. Calkins over 10 yearsYou should submit this as a PR I could use this. Maybe I'll just take your credit.
-
Verdi Erel Ergün almost 10 yearsChecking the length on each iteration is very expensive; it's better to assign the length to a variable
-
Ben Lesh almost 10 years@VerdiErelErgün "very expensive"? How many times per ms do you expact this to get hit? It's a one-time call to set up some bindings. Micro-optimization wasn't really the point here... But yes, one could
for(var i = 0, len = events.length; i < len; i++) { ... }
... or evenvar i = events.length; while(i--) { ... }
if they really cared to. -
Dmitry Gonchar over 8 years@BenLesh Any idea how to make this work with an isolated scope? Or just create a factory method and pass scope to it?
-
cipak over 7 yearsyou should modify
$rootScope.__proto__.$on
(or$rootScope.constructor.prototype.$on
) if you want child scopes to also inherit the modified function. -
Roi about 7 yearsI wrote this on the fly... but you need to be able to end listeners too... app.run(function($rootScope) { $rootScope.$onMany = function(events, fn) { var listeners = {} for(var i = 0; i < events.length; i++) { listeners[events[i]] = this.$on(events[i], fn); } return listeners; } });