diff --git a/packages/core/src/hydration/annotate.ts b/packages/core/src/hydration/annotate.ts index bec64318f0a..5d390e304a4 100644 --- a/packages/core/src/hydration/annotate.ts +++ b/packages/core/src/hydration/annotate.ts @@ -393,9 +393,6 @@ function serializeLView(lView: LView, context: HydrationContext): SerializedView for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) { const tNode = tView.data[i] as TNode; const noOffsetIndex = i - HEADER_OFFSET; - if (nativeElementsToEventTypes) { - setJSActionAttribute(tNode, lView[i], nativeElementsToEventTypes); - } // Attempt to serialize any i18n data for the given slot. We do this first, as i18n // has its own process for serialization. @@ -434,6 +431,13 @@ function serializeLView(lView: LView, context: HydrationContext): SerializedView appendDisconnectedNodeIndex(ngh, tNode); continue; } + + if (nativeElementsToEventTypes) { + // Attach `jsaction` attribute to elements that have registered listeners, + // thus potentially having a need to do an event replay. + setJSActionAttribute(tNode, lView[i], nativeElementsToEventTypes); + } + if (Array.isArray(tNode.projection)) { for (const projectionHeadTNode of tNode.projection) { // We may have `null`s in slots with no projected content. diff --git a/packages/platform-server/test/event_replay_spec.ts b/packages/platform-server/test/event_replay_spec.ts index ec657e82d50..1954b2358ff 100644 --- a/packages/platform-server/test/event_replay_spec.ts +++ b/packages/platform-server/test/event_replay_spec.ts @@ -103,6 +103,32 @@ describe('event replay', () => { } } + it('should work for elements with local refs', async () => { + const onClickSpy = jasmine.createSpy(); + + @Component({ + selector: 'app', + standalone: true, + template: ` + + `, + }) + class AppComponent { + onClick = onClickSpy; + } + const html = await ssr(AppComponent); + const ssrContents = getAppContents(html); + render(doc, ssrContents); + resetTViewsFor(AppComponent); + const btn = doc.getElementById('btn')!; + btn.click(); + const appRef = await hydrate(doc, AppComponent, { + hydrationFeatures: [withEventReplay()], + }); + appRef.tick(); + expect(onClickSpy).toHaveBeenCalled(); + }); + it('should route to the appropriate component with content projection', async () => { const outerOnClickSpy = jasmine.createSpy(); const innerOnClickSpy = jasmine.createSpy();