Skip to content

Commit 3439cc2

Browse files
iterianiAndrewKushnir
authored andcommitted
fix(core): Account for addEventListener to be passed a Window or Document. (angular#57282)
This happened to work for other event listeners since both had a addEventListener method. PR Close angular#57282
1 parent ca55b3d commit 3439cc2

File tree

2 files changed

+49
-7
lines changed

2 files changed

+49
-7
lines changed

packages/core/src/event_delegation_utils.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,25 @@ export class GlobalEventDelegation implements OnDestroy {
9393
return isEarlyEventType(eventType);
9494
}
9595

96-
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
97-
this.eventContractDetails.instance!.addEvent(eventName);
98-
sharedStashFunction(element, eventName, handler);
99-
getActionCache(element)[eventName] = '';
100-
return () => this.removeEventListener(element, eventName, handler);
96+
addEventListener(element: HTMLElement, eventType: string, handler: Function): Function {
97+
// Note: contrary to the type, Window and Document can be passed in
98+
// as well.
99+
if (element.nodeType === Node.ELEMENT_NODE) {
100+
this.eventContractDetails.instance!.addEvent(eventType);
101+
getActionCache(element)[eventType] = '';
102+
sharedStashFunction(element, eventType, handler);
103+
} else {
104+
element.addEventListener(eventType, handler as EventListener);
105+
}
106+
return () => this.removeEventListener(element, eventType, handler);
101107
}
102108

103109
removeEventListener(element: HTMLElement, eventType: string, callback: Function): void {
104-
getActionCache(element)[eventType] = undefined;
110+
if (element.nodeType === Node.ELEMENT_NODE) {
111+
getActionCache(element)[eventType] = undefined;
112+
} else {
113+
element.removeEventListener(eventType, callback as EventListener);
114+
}
105115
}
106116
}
107117

packages/core/test/event_dispatch/event_dispatch_spec.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Component, Renderer2, inject, ɵprovideGlobalEventDelegation} from '@angular/core';
9+
import {
10+
Component,
11+
HostListener,
12+
Renderer2,
13+
inject,
14+
ɵprovideGlobalEventDelegation,
15+
} from '@angular/core';
1016
import {ComponentFixture, TestBed} from '@angular/core/testing';
1117

1218
function configureTestingModule(components: unknown[]) {
@@ -216,5 +222,31 @@ describe('event dispatch', () => {
216222
bottomEl.click();
217223
expect(onClickSpy).toHaveBeenCalledTimes(2);
218224
});
225+
it('should allow host listening on the window', async () => {
226+
const onClickSpy = jasmine.createSpy();
227+
@Component({
228+
standalone: true,
229+
selector: 'app',
230+
template: `
231+
<div id="top">
232+
<div id="bottom"></div>
233+
</div>
234+
`,
235+
})
236+
class SimpleComponent {
237+
renderer = inject(Renderer2);
238+
destroy!: Function;
239+
@HostListener('window:click', ['$event.target'])
240+
listen(el: Element) {
241+
onClickSpy();
242+
}
243+
}
244+
configureTestingModule([SimpleComponent]);
245+
fixture = TestBed.createComponent(SimpleComponent);
246+
const nativeElement = fixture.debugElement.nativeElement;
247+
const bottomEl = nativeElement.querySelector('#bottom')!;
248+
bottomEl.click();
249+
expect(onClickSpy).toHaveBeenCalledTimes(1);
250+
});
219251
});
220252
});

0 commit comments

Comments
 (0)