Is there a built in way to stop $broadcast
events from going down the scope chain?
The event object passed by a $broadcast
event does not have a stopPropagation
method (as the docs on $rootScope mention.) However this merged pull request suggest that $broadcast
events can have stopPropagation
called on them.
Snippets from angularJS 1.1.2 source code:
$emit: function(name, args) {
// ....
event = {
name: name,
targetScope: scope,
stopPropagation: function() {
stopPropagation = true;
},
preventDefault: function() {
event.defaultPrevented = true;
},
defaultPrevented: false
},
// ....
}
$broadcast: function(name, args) {
// ...
event = {
name: name,
targetScope: target,
preventDefault: function() {
event.defaultPrevented = true;
},
defaultPrevented: false
},
// ...
}
As you can see event object in $broadcast not have "stopPropagation".
Instead of stopPropagation you can use preventDefault in order to mark event as "not need to handle this event". This not stop event propagation but this will tell the children scopes: "not need to handle this event"
Example: http://jsfiddle.net/C8EqT/1/
Since broadcast does not have the stopPropagation method,you need to use the defaultPrevented property and this will make sense in recursive directives.
Have a look at this plunker here:Plunkr
$scope.$on('test', function(event) {
if (!event.defaultPrevented) {
event.defaultPrevented = true;
console.log('Handle event here for the root node only.');
}
});
I implemented an event thief for this purpose:
.factory("stealEvent", [function () {
/**
* If event is already "default prevented", noop.
* If event isn't "default prevented", executes callback.
* If callback returns a truthy value or undefined,
* stops event propagation if possible, and flags event as "default prevented".
*/
return function (callback) {
return function (event) {
if (!event.defaultPrevented) {
var stopEvent = callback.apply(null, arguments);
if (typeof stopEvent === "undefined" || stopEvent) {
event.stopPropagation && event.stopPropagation();
event.preventDefault();
}
}
};
};
}]);
To use:
$scope.$on("AnyEvent", stealEvent(function (event, anyOtherParameter) {
if ($scope.keepEvent) {
// do some stuff with anyOtherParameter
return true; // steal event
} else {
return false; // let event available for other listeners
}
}));
$scope.$on("AnyOtherEvent", stealEvent(function (event, anyOtherParameter) {
// do some stuff with anyOtherParameter, event stolen by default
}));