diff --git a/packages/core/src/render3/instructions/listener.ts b/packages/core/src/render3/instructions/listener.ts index f37d6cb0a23..bcb85b26ef1 100644 --- a/packages/core/src/render3/instructions/listener.ts +++ b/packages/core/src/render3/instructions/listener.ts @@ -210,7 +210,7 @@ export function listenerInternal( (existingListener).__ngLastListenerFn__ = listenerFn; processOutputs = false; } else { - listenerFn = wrapListener(tNode, lView, context, listenerFn); + listenerFn = wrapListener(tNode, lView, listenerFn); stashEventListener(target as RElement, eventName, listenerFn); const cleanupFn = renderer.listen(target as RElement, eventName, listenerFn); ngDevMode && ngDevMode.rendererAddEventListener++; @@ -221,7 +221,7 @@ export function listenerInternal( } else { // Even if there is no native listener to add, we still need to wrap the listener so that OnPush // ancestors are marked dirty when an event occurs. - listenerFn = wrapListener(tNode, lView, context, listenerFn); + listenerFn = wrapListener(tNode, lView, listenerFn); } if (processOutputs) { @@ -232,33 +232,13 @@ export function listenerInternal( for (let i = 0; i < hostDirectiveOutputConfig.length; i += 2) { const index = hostDirectiveOutputConfig[i] as number; const lookupName = hostDirectiveOutputConfig[i + 1] as string; - listenToOutput( - tNode, - tView, - lView, - index, - lookupName, - eventName, - listenerFn, - lCleanup, - tCleanup, - ); + listenToOutput(tNode, lView, index, lookupName, eventName, listenerFn); } } if (outputConfig && outputConfig.length) { for (const index of outputConfig) { - listenToOutput( - tNode, - tView, - lView, - index, - eventName, - eventName, - listenerFn, - lCleanup, - tCleanup, - ); + listenToOutput(tNode, lView, index, eventName, eventName, listenerFn); } } } diff --git a/packages/core/src/render3/view/directive_outputs.ts b/packages/core/src/render3/view/directive_outputs.ts index ee08bdec0bf..c7b47921275 100644 --- a/packages/core/src/render3/view/directive_outputs.ts +++ b/packages/core/src/render3/view/directive_outputs.ts @@ -9,7 +9,7 @@ import {assertIndexInRange} from '../../util/assert'; import {DirectiveDef} from '../interfaces/definition'; import {TNode} from '../interfaces/node'; -import {CONTEXT, LView, TVIEW, TView} from '../interfaces/view'; +import {LView, TVIEW} from '../interfaces/view'; import {getOrCreateLViewCleanup, getOrCreateTViewCleanup} from '../util/view_utils'; import {wrapListener} from './listeners'; @@ -26,23 +26,19 @@ export function createOutputListener( eventName: string, ) { // TODO(pk): decouple checks from the actual binding - const wrappedListener = wrapListener(tNode, lView, lView[CONTEXT], listenerFn); + const wrappedListener = wrapListener(tNode, lView, listenerFn); - // TODO(pk): simplify signature of listenToDirectiveOutput - listenToDirectiveOutput(tNode, lView[TVIEW], lView, targetDef, eventName, wrappedListener); + listenToDirectiveOutput(tNode, lView, targetDef, eventName, wrappedListener); } /** Listens to an output on a specific directive. */ function listenToDirectiveOutput( tNode: TNode, - tView: TView, lView: LView, target: DirectiveDef, eventName: string, listenerFn: (e?: any) => any, ): boolean { - const tCleanup = tView.firstCreatePass ? getOrCreateTViewCleanup(tView) : null; - const lCleanup = getOrCreateLViewCleanup(lView); let hostIndex: number | null = null; let hostDirectivesStart: number | null = null; let hostDirectivesEnd: number | null = null; @@ -75,14 +71,11 @@ function listenToDirectiveOutput( hasOutput = true; listenToOutput( tNode, - tView, lView, index, hostDirectiveOutputs[i + 1] as string, eventName, listenerFn, - lCleanup, - tCleanup, ); } else if (index > hostDirectivesEnd) { break; @@ -93,17 +86,7 @@ function listenToDirectiveOutput( if (target.outputs.hasOwnProperty(eventName)) { ngDevMode && assertIndexInRange(lView, hostIndex); hasOutput = true; - listenToOutput( - tNode, - tView, - lView, - hostIndex, - eventName, - eventName, - listenerFn, - lCleanup, - tCleanup, - ); + listenToOutput(tNode, lView, hostIndex, eventName, eventName, listenerFn); } return hasOutput; @@ -111,18 +94,16 @@ function listenToDirectiveOutput( export function listenToOutput( tNode: TNode, - tView: TView, lView: LView, - index: number, + directiveIndex: number, lookupName: string, eventName: string, listenerFn: (e?: any) => any, - lCleanup: any[], - tCleanup: any[] | null, ) { - ngDevMode && assertIndexInRange(lView, index); - const instance = lView[index]; - const def = tView.data[index] as DirectiveDef; + ngDevMode && assertIndexInRange(lView, directiveIndex); + const instance = lView[directiveIndex]; + const tView = lView[TVIEW]; + const def = tView.data[directiveIndex] as DirectiveDef; const propertyName = def.outputs[lookupName]; const output = instance[propertyName]; @@ -130,6 +111,9 @@ export function listenToOutput( throw new Error(`@Output ${propertyName} not initialized in '${instance.constructor.name}'.`); } + // TODO(pk): introduce utility to store cleanup or find a different way of sharing code with listener + const tCleanup = tView.firstCreatePass ? getOrCreateTViewCleanup(tView) : null; + const lCleanup = getOrCreateLViewCleanup(lView); const subscription = (output as SubscribableOutput).subscribe(listenerFn); const idx = lCleanup.length; lCleanup.push(listenerFn, subscription); diff --git a/packages/core/src/render3/view/listeners.ts b/packages/core/src/render3/view/listeners.ts index a65ddd17c09..8e562d3d8b9 100644 --- a/packages/core/src/render3/view/listeners.ts +++ b/packages/core/src/render3/view/listeners.ts @@ -11,7 +11,7 @@ import {setActiveConsumer} from '@angular/core/primitives/signals'; import {NotificationSource} from '../../change_detection/scheduling/zoneless_scheduling'; import {TNode} from '../interfaces/node'; import {isComponentHost} from '../interfaces/type_checks'; -import {INJECTOR, LView} from '../interfaces/view'; +import {CONTEXT, INJECTOR, LView} from '../interfaces/view'; import {getComponentLViewByIndex} from '../util/view_utils'; import {profiler} from '../profiler'; import {ProfilerEvent} from '../profiler_types'; @@ -31,7 +31,6 @@ import {markViewDirty} from '../instructions/mark_view_dirty'; export function wrapListener( tNode: TNode, lView: LView<{} | null>, - context: {} | null, listenerFn: (e?: any) => any, ): EventListener { // Note: we are performing most of the work in the listener function itself @@ -48,6 +47,7 @@ export function wrapListener( const startView = isComponentHost(tNode) ? getComponentLViewByIndex(tNode.index, lView) : lView; markViewDirty(startView, NotificationSource.Listener); + const context = lView[CONTEXT]; let result = executeListenerWithErrorHandling(lView, context, listenerFn, e); // A just-invoked listener function might have coalesced listeners so we need to check for // their presence and invoke as needed. diff --git a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json index 681c05c816e..a9b9e9f058f 100644 --- a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json @@ -388,8 +388,10 @@ "getNodeInjectable", "getNullInjector", "getOrCreateInjectable", + "getOrCreateLViewCleanup", "getOrCreateNodeInjectorForNode", "getOrCreateTNode", + "getOrCreateTViewCleanup", "getOrCreateViewRefs", "getOwnDefinition", "getParentInjectorIndex", diff --git a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json index d09d6c770a8..f1f78180357 100644 --- a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json @@ -375,8 +375,10 @@ "getNodeInjectable", "getNullInjector", "getOrCreateInjectable", + "getOrCreateLViewCleanup", "getOrCreateNodeInjectorForNode", "getOrCreateTNode", + "getOrCreateTViewCleanup", "getOrCreateViewRefs", "getOwnDefinition", "getParentInjectorIndex", diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 3fc46ae8117..1d19fbabb73 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -319,8 +319,10 @@ "getNodeInjectable", "getNullInjector", "getOrCreateInjectable", + "getOrCreateLViewCleanup", "getOrCreateNodeInjectorForNode", "getOrCreateTNode", + "getOrCreateTViewCleanup", "getOrCreateViewRefs", "getOwnDefinition", "getParentInjectorIndex",