diff --git a/packages/animations/browser/src/render/transition_animation_engine.ts b/packages/animations/browser/src/render/transition_animation_engine.ts
index b3ec5bc052..f3ef0f80bc 100644
--- a/packages/animations/browser/src/render/transition_animation_engine.ts
+++ b/packages/animations/browser/src/render/transition_animation_engine.ts
@@ -437,11 +437,14 @@ export class AnimationTransitionNamespace {
if (containsPotentialParentTransition) {
engine.markElementAsRemoved(this.id, element, false, context);
} else {
- // we do this after the flush has occurred such
- // that the callbacks can be fired
- engine.afterFlush(() => this.clearElementCache(element));
- engine.destroyInnerAnimations(element);
- engine._onRemovalComplete(element, context);
+ const removalFlag = element[REMOVAL_FLAG];
+ if (!removalFlag || removalFlag === NULL_REMOVAL_STATE) {
+ // we do this after the flush has occurred such
+ // that the callbacks can be fired
+ engine.afterFlush(() => this.clearElementCache(element));
+ engine.destroyInnerAnimations(element);
+ engine._onRemovalComplete(element, context);
+ }
}
}
diff --git a/packages/core/test/animation/animation_integration_spec.ts b/packages/core/test/animation/animation_integration_spec.ts
index 4087eff1f4..d2034fb6a2 100644
--- a/packages/core/test/animation/animation_integration_spec.ts
+++ b/packages/core/test/animation/animation_integration_spec.ts
@@ -932,6 +932,53 @@ const DEFAULT_COMPONENT_ID = '1';
expect(fixture.debugElement.nativeElement.children.length).toBe(0);
}));
+ it('should wait for child animations before removing parent', fakeAsync(() => {
+ @Component({
+ template: '
Hello there
', + animations: [trigger( + 'childTrigger', + [transition( + ':leave', [style({opacity: 1}), animate('200ms', style({opacity: 0}))])])] + }) + class ChildCmp { + } + + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toBe(0); + + fixture.componentInstance.exp = false; + fixture.detectChanges(); + expect(fixture.nativeElement.children.length).toBe(1); + + engine.flush(); + expect(getLog().length).toBe(1); + + const player = getLog()[0]; + expect(player.keyframes).toEqual([ + {opacity: '1', offset: 0}, + {opacity: '0', offset: 1}, + ]); + + player.finish(); + flushMicrotasks(); + expect(fixture.nativeElement.children.length).toBe(0); + })); + // animationRenderer => nonAnimationRenderer it('should trigger a leave animation when the outer components element binding updates on the host component element', fakeAsync(() => {