-
Notifications
You must be signed in to change notification settings - Fork 27.3k
fix($rootScope): avoid unstable reference in $broadcast event #7445
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1572,6 +1572,10 @@ describe('Scope', function() { | |
| }); | ||
| grandChild.$emit('myEvent'); | ||
| expect(event).toBeDefined(); | ||
|
|
||
| // Asynchronous expectation : current & target should be the same as above | ||
| expect(event.targetScope).toBe(grandChild); | ||
| expect(event.currentScope).toBe(child); | ||
| }); | ||
|
|
||
|
|
||
|
|
@@ -1693,26 +1697,41 @@ describe('Scope', function() { | |
| expect(result.name).toBe('some'); | ||
| expect(result.targetScope).toBe(child1); | ||
| }); | ||
|
|
||
| it('should have preventDefault method and defaultPrevented property', function() { | ||
| var event = child2.$broadcast('myEvent'); | ||
| expect(event.defaultPrevented).toBe(false); | ||
|
|
||
| grandChild21.$on('myEvent', function(event) { | ||
| event.preventDefault(); | ||
| }); | ||
| event = child2.$broadcast('myEvent'); | ||
| expect(event.defaultPrevented).toBe(true); | ||
| }); | ||
|
|
||
| }); | ||
|
|
||
|
|
||
| describe('listener', function() { | ||
| it('should receive event object', inject(function($rootScope) { | ||
| var scope = $rootScope, | ||
| child = scope.$new(), | ||
| grandChild = child.$new(), | ||
| event; | ||
|
|
||
| child.$on('fooEvent', function(e) { | ||
| expect(e.targetScope).toBe(scope); | ||
| expect(e.currentScope).toBe(child); | ||
| expect(e.name).toBe('fooEvent'); | ||
| event = e; | ||
| }); | ||
| scope.$broadcast('fooEvent'); | ||
|
|
||
| expect(event.name).toBe('fooEvent'); | ||
| // Asynchronous expectation : current & target should be the same as above | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wat
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's not asynchronous, and you should not give the impression that it's asynchronous
That's a test case you wrote yourself, it's not present in angular core! Just remove the "Asynchronous expectation..." bit
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You understand that I'm referring to the comment, right? That scope event handler is not being called asynchronously, there is nothing asynchronous happening here, it's all within a single turn of the event loop
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops. No, I didn't. Sorry for that. |
||
| expect(event.targetScope).toBe(scope); | ||
| expect(event.currentScope).toBe(child); | ||
| })); | ||
|
|
||
|
|
||
| it('should support passing messages as varargs', inject(function($rootScope) { | ||
| var scope = $rootScope, | ||
| child = scope.$new(), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of this function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It defines a javascript class which is instantiated for each listener among the tree of scopes.
By this way, each listener received a dedicated event with a stable
currentScopeproperty.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But why does this class need a
preventDefault? There is not action being taken there other then alteringthis.defaultPrevented. This seems misleading to me.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I retained the existing
preventDefault.I asked myself for the purpose of this property. Perhaps to be consistent with DOM events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel it should be removed, this may have been a mistake in the angular api. Events without a native default should not have a preventDefault method. @lgalfaso thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think they should have
preventDefaulteven when in the case of a$broadcastit does nothingThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lgalfaso why? I don't believe it does anything for
$emiteither. Its just basically a misleadingnoop.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Fresheyeball the event used to have a function called
preventDefaultand that should not be removed, user may call it (even if it does nothing).In the case of
$emit, callingpreventDefaultdoes prevent the event from going upThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lgalfaso thats even worse. Why would
preventDefaultbestopPropagation? There is no browser default, so there should be no prevent default. That is exactly why this is bad.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Fresheyeball There are two things involved there
This PR is to fix an existing issue with events
currentparameter (that affects$broadcastand$emit). As part of this fix, it is required that this does not break what people expect from the API, this includes that there is a function calledpreventDefault. How this function works is not part of this PR.Now,
preventDefaultis part of the DOM standard http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Event-preventDefault. This patch is not about adding/removing or being consistent on the fact that there is apreventDefaultfunction and notstopPropagationnor on the fact thatpreventDefaultworks in one way when calling$broadcastand in another way when calling$emit. If you feel that this is a limitation you are welcome to put a PR in place