diff --git a/packages/core/src/render3/instructions/defer_events.ts b/packages/core/src/render3/instructions/defer_events.ts index a64e03bb45cf8..4df351f10afb9 100644 --- a/packages/core/src/render3/instructions/defer_events.ts +++ b/packages/core/src/render3/instructions/defer_events.ts @@ -24,6 +24,9 @@ const interactionTriggers = new WeakMap(); /** Names of the events considered as interaction events. */ const interactionEventNames = ['click', 'keydown'] as const; +/** Names of the events considered as hover events. */ +const hoverEventNames = ['mouseenter', 'focusin']; + /** Object keeping track of registered callbacks for a deferred block trigger. */ class DeferEventEntry { callbacks = new Set<() => void>(); @@ -103,7 +106,9 @@ export function onHover( // Ensure that the handler runs in the NgZone since it gets // registered in `afterRender` which runs outside. injector.get(NgZone).run(() => { - trigger.addEventListener('mouseenter', entry!.listener, eventListenerOptions); + for (const name of hoverEventNames) { + trigger.addEventListener(name, entry!.listener, eventListenerOptions); + } }); } @@ -114,7 +119,9 @@ export function onHover( callbacks.delete(callback); if (callbacks.size === 0) { - trigger.removeEventListener('mouseenter', listener, eventListenerOptions); + for (const name of hoverEventNames) { + trigger.removeEventListener(name, listener, eventListenerOptions); + } hoverTriggers.delete(trigger); } }; diff --git a/packages/core/test/acceptance/defer_spec.ts b/packages/core/test/acceptance/defer_spec.ts index ff4bfd9bc544d..b9301e46421b1 100644 --- a/packages/core/test/acceptance/defer_spec.ts +++ b/packages/core/test/acceptance/defer_spec.ts @@ -2499,8 +2499,9 @@ describe('@defer', () => { fixture.detectChanges(); flush(); - expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledTimes(2); expect(spy).toHaveBeenCalledWith('mouseenter', jasmine.any(Function), jasmine.any(Object)); + expect(spy).toHaveBeenCalledWith('focusin', jasmine.any(Function), jasmine.any(Object)); })); it('should unbind the trigger events when the trigger is destroyed', fakeAsync(() => { @@ -2533,8 +2534,9 @@ describe('@defer', () => { fixture.componentInstance.renderBlock = false; fixture.detectChanges(); - expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledTimes(2); expect(spy).toHaveBeenCalledWith('mouseenter', jasmine.any(Function), jasmine.any(Object)); + expect(spy).toHaveBeenCalledWith('focusin', jasmine.any(Function), jasmine.any(Object)); })); it('should unbind the trigger events when the deferred block is destroyed', fakeAsync(() => { @@ -2568,8 +2570,9 @@ describe('@defer', () => { fixture.componentInstance.renderBlock = false; fixture.detectChanges(); - expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledTimes(2); expect(spy).toHaveBeenCalledWith('mouseenter', jasmine.any(Function), jasmine.any(Object)); + expect(spy).toHaveBeenCalledWith('focusin', jasmine.any(Function), jasmine.any(Object)); })); it('should bind the trigger events inside the NgZone', fakeAsync(() => { @@ -2595,7 +2598,10 @@ describe('@defer', () => { }); fixture.detectChanges(); - expect(eventsInZone).toEqual({mouseenter: true}); + expect(eventsInZone).toEqual({ + mouseenter: true, + focusin: true, + }); })); it('should prefetch resources on hover', fakeAsync(() => {