diff --git a/packages/core/src/render3/view/listeners.ts b/packages/core/src/render3/view/listeners.ts
index 3fcb4b39bc0..de94331c113 100644
--- a/packages/core/src/render3/view/listeners.ts
+++ b/packages/core/src/render3/view/listeners.ts
@@ -163,23 +163,33 @@ export function listenToDomEvent(
stashEventListenerImpl(lView, target, eventName, wrappedListener);
const cleanupFn = renderer.listen(target as RElement, eventName, wrappedListener);
- const idxOrTargetGetter = eventTargetResolver
- ? (_lView: LView) => eventTargetResolver(unwrapRNode(_lView[tNode.index]))
- : tNode.index;
- storeListenerCleanup(
- idxOrTargetGetter,
- tView,
- lView,
- eventName,
- wrappedListener,
- cleanupFn,
- false,
- );
+ // We skip cleaning up animation event types to ensure leaving animation events can be used.
+ // These events should be automatically garbage collected anyway after the element is
+ // removed from the DOM.
+ if (!isAnimationEventType(eventName)) {
+ const idxOrTargetGetter = eventTargetResolver
+ ? (_lView: LView) => eventTargetResolver(unwrapRNode(_lView[tNode.index]))
+ : tNode.index;
+
+ storeListenerCleanup(
+ idxOrTargetGetter,
+ tView,
+ lView,
+ eventName,
+ wrappedListener,
+ cleanupFn,
+ false,
+ );
+ }
}
return hasCoalesced;
}
+function isAnimationEventType(eventName: string): boolean {
+ return eventName.startsWith('animation') || eventName.startsWith('transition');
+}
+
/**
* A utility function that checks if a given element has already an event handler registered for an
* event with a specified name. The TView.cleanup data structure is used to find out which events
diff --git a/packages/core/test/acceptance/animation_spec.ts b/packages/core/test/acceptance/animation_spec.ts
index 5441bcefe2a..979097a479b 100644
--- a/packages/core/test/acceptance/animation_spec.ts
+++ b/packages/core/test/acceptance/animation_spec.ts
@@ -47,14 +47,20 @@ describe('Animation', () => {
`;
it('should delay element removal when an animation is specified', fakeAsync(() => {
+ const logSpy = jasmine.createSpy('logSpy');
@Component({
selector: 'test-cmp',
styles: styles,
- template: '
@if (show()) {
I should fade
}
',
+ template:
+ '@if (show()) {
I should fade
}
',
encapsulation: ViewEncapsulation.None,
})
class TestComponent {
show = signal(true);
+
+ logMe(event: AnimationEvent) {
+ logSpy();
+ }
}
TestBed.configureTestingModule({animationsEnabled: true});
@@ -76,6 +82,7 @@ describe('Animation', () => {
new AnimationEvent('animationend', {animationName: 'fade-out'}),
);
expect(fixture.nativeElement.outerHTML).not.toContain('class="fade"');
+ expect(logSpy).toHaveBeenCalled();
}));
it('should remove right away when animations are disabled', fakeAsync(() => {
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 2796d0f122c..cc9ac4a68db 100644
--- a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json
+++ b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json
@@ -696,6 +696,7 @@
"invokeHostBindingsInCreationMode",
"isAbstractControlOptions",
"isAngularZoneProperty",
+ "isAnimationEventType",
"isAnimationProp",
"isApplicationBootstrapConfig",
"isArrayLike",
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 aaa5ac72275..1aa247c42cf 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
@@ -697,6 +697,7 @@
"invokeDirectivesHostBindings",
"invokeHostBindingsInCreationMode",
"isAngularZoneProperty",
+ "isAnimationEventType",
"isAnimationProp",
"isApplicationBootstrapConfig",
"isArrayLike",
diff --git a/packages/core/test/bundling/router/bundle.golden_symbols.json b/packages/core/test/bundling/router/bundle.golden_symbols.json
index a245562b1b1..5506fc8170a 100644
--- a/packages/core/test/bundling/router/bundle.golden_symbols.json
+++ b/packages/core/test/bundling/router/bundle.golden_symbols.json
@@ -791,6 +791,7 @@
"invokeHostBindingsInCreationMode",
"isActiveMatchOptions",
"isAngularZoneProperty",
+ "isAnimationEventType",
"isAnimationProp",
"isApplicationBootstrapConfig",
"isArrayLike",