Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
fix(Scope): $broadcast and $emit should set event.currentScope to null
Browse files Browse the repository at this point in the history
When a event is finished propagating through Scope hierarchy the event's `currentScope` property
should be reset to `null` to avoid accidental use of this property in asynchronous event handlers.

In the previous code, the event's property would contain a reference to the last Scope instance that
was visited during the traversal, which is unlikely what the code trying to grab scope reference expects.

BREAKING CHANGE: $broadcast and $emit will now reset the `currentScope` property of the event to
null once the event finished propagating. If any code depends on asynchronously accessing thei
`currentScope` property, it should be migrated to use `targetScope` instead. All of these cases
should be considered programming bugs.

Closes #7445
Closes #7523
  • Loading branch information
IgorMinar committed May 21, 2014
1 parent def5b57 commit 82f45ae
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 5 deletions.
11 changes: 9 additions & 2 deletions src/ng/rootScope.js
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,8 @@ function $RootScopeProvider(){
*
* - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
* `$broadcast`-ed.
* - `currentScope` - `{Scope}`: the current scope which is handling the event.
* - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
* event propagates through the scope hierarchy, this property is set to null.
* - `name` - `{string}`: name of the event.
* - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
* further event propagation (available only for events that were `$emit`-ed).
Expand Down Expand Up @@ -1065,11 +1066,16 @@ function $RootScopeProvider(){
}
}
//if any listener on the current scope stops propagation, prevent bubbling
if (stopPropagation) return event;
if (stopPropagation) {
event.currentScope = null;
return event;
}
//traverse upwards
scope = scope.$parent;
} while (scope);

event.currentScope = null;

return event;
},

Expand Down Expand Up @@ -1142,6 +1148,7 @@ function $RootScopeProvider(){
}
}

event.currentScope = null;
return event;
}
};
Expand Down
40 changes: 37 additions & 3 deletions test/ng/rootScopeSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1563,15 +1563,30 @@ describe('Scope', function() {

describe('event object', function() {
it('should have methods/properties', function() {
var event;
var eventFired = false;

child.$on('myEvent', function(e) {
expect(e.targetScope).toBe(grandChild);
expect(e.currentScope).toBe(child);
expect(e.name).toBe('myEvent');
eventFired = true;
});
grandChild.$emit('myEvent');
expect(eventFired).toBe(true);
});


it("should have it's `currentScope` property set to null after emit", function() {
var event;

child.$on('myEvent', function(e) {
event = e;
});
grandChild.$emit('myEvent');
expect(event).toBeDefined();

expect(event.currentScope).toBe(null);
expect(event.targetScope).toBe(grandChild);
expect(event.name).toBe('myEvent');
});


Expand All @@ -1584,6 +1599,7 @@ describe('Scope', function() {
});
event = grandChild.$emit('myEvent');
expect(event.defaultPrevented).toBe(true);
expect(event.currentScope).toBe(null);
});
});
});
Expand Down Expand Up @@ -1698,6 +1714,24 @@ describe('Scope', function() {

describe('listener', function() {
it('should receive event object', inject(function($rootScope) {
var scope = $rootScope,
child = scope.$new(),
eventFired = false;

child.$on('fooEvent', function(event) {
eventFired = true;
expect(event.name).toBe('fooEvent');
expect(event.targetScope).toBe(scope);
expect(event.currentScope).toBe(child);
});
scope.$broadcast('fooEvent');

expect(eventFired).toBe(true);
}));


it("should have the event's `currentScope` property set to null after broadcast",
inject(function($rootScope) {
var scope = $rootScope,
child = scope.$new(),
event;
Expand All @@ -1709,7 +1743,7 @@ describe('Scope', function() {

expect(event.name).toBe('fooEvent');
expect(event.targetScope).toBe(scope);
expect(event.currentScope).toBe(child);
expect(event.currentScope).toBe(null);
}));


Expand Down

0 comments on commit 82f45ae

Please sign in to comment.