fix(core): Account for addEventListener to be passed a Window or Document. (#57282)

This happened to work for other event listeners since both had a
addEventListener method.

PR Close #57282
This commit is contained in:
Thomas Nguyen 2024-08-06 14:45:05 -07:00 committed by Andrew Kushnir
parent 5401332b0e
commit e39b22a932
2 changed files with 49 additions and 7 deletions

View file

@ -93,15 +93,25 @@ export class GlobalEventDelegation implements OnDestroy {
return isEarlyEventType(eventType);
}
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
this.eventContractDetails.instance!.addEvent(eventName);
sharedStashFunction(element, eventName, handler);
getActionCache(element)[eventName] = '';
return () => this.removeEventListener(element, eventName, handler);
addEventListener(element: HTMLElement, eventType: string, handler: Function): Function {
// Note: contrary to the type, Window and Document can be passed in
// as well.
if (element.nodeType === Node.ELEMENT_NODE) {
this.eventContractDetails.instance!.addEvent(eventType);
getActionCache(element)[eventType] = '';
sharedStashFunction(element, eventType, handler);
} else {
element.addEventListener(eventType, handler as EventListener);
}
return () => this.removeEventListener(element, eventType, handler);
}
removeEventListener(element: HTMLElement, eventType: string, callback: Function): void {
getActionCache(element)[eventType] = undefined;
if (element.nodeType === Node.ELEMENT_NODE) {
getActionCache(element)[eventType] = undefined;
} else {
element.removeEventListener(eventType, callback as EventListener);
}
}
}

View file

@ -6,7 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Component, Renderer2, inject, ɵprovideGlobalEventDelegation} from '@angular/core';
import {
Component,
HostListener,
Renderer2,
inject,
ɵprovideGlobalEventDelegation,
} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
function configureTestingModule(components: unknown[]) {
@ -216,5 +222,31 @@ describe('event dispatch', () => {
bottomEl.click();
expect(onClickSpy).toHaveBeenCalledTimes(2);
});
it('should allow host listening on the window', async () => {
const onClickSpy = jasmine.createSpy();
@Component({
standalone: true,
selector: 'app',
template: `
<div id="top">
<div id="bottom"></div>
</div>
`,
})
class SimpleComponent {
renderer = inject(Renderer2);
destroy!: Function;
@HostListener('window:click', ['$event.target'])
listen(el: Element) {
onClickSpy();
}
}
configureTestingModule([SimpleComponent]);
fixture = TestBed.createComponent(SimpleComponent);
const nativeElement = fixture.debugElement.nativeElement;
const bottomEl = nativeElement.querySelector('#bottom')!;
bottomEl.click();
expect(onClickSpy).toHaveBeenCalledTimes(1);
});
});
});