diff --git a/packages/animations/browser/src/render/transition_animation_engine.ts b/packages/animations/browser/src/render/transition_animation_engine.ts index fa3e1419b0..9544487926 100644 --- a/packages/animations/browser/src/render/transition_animation_engine.ts +++ b/packages/animations/browser/src/render/transition_animation_engine.ts @@ -734,8 +734,8 @@ export class TransitionAnimationEngine { // if a unmatched transition is queued to go then it SHOULD NOT render // an animation and cancel the previously running animations. - if (entry.isFallbackTransition && !instruction.isRemovalTransition) { - eraseStyles(element, instruction.fromStyles); + if (entry.isFallbackTransition) { + player.onStart(() => eraseStyles(element, instruction.fromStyles)); player.onDestroy(() => setStyles(element, instruction.toStyles)); skippedPlayers.push(player); return; @@ -790,6 +790,14 @@ export class TransitionAnimationEngine { } }); + skippedPlayers.forEach(player => { + const element = player.element; + const previousPlayers = + this._getPreviousPlayers(element, false, player.namespaceId, player.triggerName, null); + previousPlayers.forEach( + prevPlayer => { getOrSetAsInMap(allPreviousPlayersMap, element, []).push(prevPlayer); }); + }); + allPreviousPlayersMap.forEach(players => players.forEach(player => player.destroy())); const leaveNodes: any[] = bodyNode && allPostStyleElements.size ? @@ -919,8 +927,8 @@ export class TransitionAnimationEngine { afterFlushAnimationsDone(callback: () => any) { this._whenQuietFns.push(callback); } private _getPreviousPlayers( - element: string, instruction: AnimationTransitionInstruction, isQueriedElement: boolean, - namespaceId?: string, triggerName?: string): TransitionAnimationPlayer[] { + element: string, isQueriedElement: boolean, namespaceId?: string, triggerName?: string, + toStateValue?: any): TransitionAnimationPlayer[] { let players: TransitionAnimationPlayer[] = []; if (isQueriedElement) { const queriedElementPlayers = this.playersByQueriedElement.get(element); @@ -930,10 +938,10 @@ export class TransitionAnimationEngine { } else { const elementPlayers = this.playersByElement.get(element); if (elementPlayers) { - const isRemovalAnimation = instruction.toState == VOID_VALUE; + const isRemovalAnimation = !toStateValue || toStateValue == VOID_VALUE; elementPlayers.forEach(player => { if (player.queued) return; - if (!isRemovalAnimation && player.triggerName != instruction.triggerName) return; + if (!isRemovalAnimation && player.triggerName != triggerName) return; players.push(player); }); } @@ -943,7 +951,7 @@ export class TransitionAnimationEngine { if (namespaceId && namespaceId != player.namespaceId) return false; if (triggerName && triggerName != player.triggerName) return false; return true; - }) + }); } return players; } @@ -970,7 +978,7 @@ export class TransitionAnimationEngine { const isQueriedElement = element !== rootElement; const players = getOrSetAsInMap(allPreviousPlayersMap, element, []); const previousPlayers = this._getPreviousPlayers( - element, instruction, isQueriedElement, targetNameSpaceId, targetTriggerName); + element, isQueriedElement, targetNameSpaceId, targetTriggerName, instruction.toState); previousPlayers.forEach(player => { const realPlayer = player.getRealPlayer() as any; if (realPlayer.beforeDestroy) { diff --git a/packages/core/test/animation/animation_integration_spec.ts b/packages/core/test/animation/animation_integration_spec.ts index b12240b1c6..6beca5de35 100644 --- a/packages/core/test/animation/animation_integration_spec.ts +++ b/packages/core/test/animation/animation_integration_spec.ts @@ -223,7 +223,7 @@ export function main() { ]); }); - it('should not cancel the previous transition if a follow-up transition is not matched', + it('should always cancel the previous transition if a follow-up transition is not matched', fakeAsync(() => { @Component({ selector: 'if-cmp', @@ -290,7 +290,7 @@ export function main() { fixture.detectChanges(); engine.flush(); - expect(engine.players.length).toEqual(1); + expect(engine.players.length).toEqual(0); expect(getLog().length).toEqual(0); flushMicrotasks(); @@ -299,7 +299,7 @@ export function main() { expect(cmp.startEvent.toState).toEqual('c'); expect(cmp.startEvent.totalTime).toEqual(0); - expect(completed).toBe(false); + expect(completed).toBe(true); })); it('should only turn a view removal as into `void` state transition', () => { diff --git a/packages/core/test/animation/animation_query_integration_spec.ts b/packages/core/test/animation/animation_query_integration_spec.ts index 6582fb55be..03e8393f65 100644 --- a/packages/core/test/animation/animation_query_integration_spec.ts +++ b/packages/core/test/animation/animation_query_integration_spec.ts @@ -984,7 +984,7 @@ export function main() { expect(count).toEqual(8); }); - it('should not cancel inner queried animations if a trigger state value changes, but isn\'t detected as a valid transition', + it('should cancel inner queried animations if a trigger state value changes, but isn\'t detected as a valid transition', () => { @Component({ selector: 'ani-cmp', @@ -1031,7 +1031,7 @@ export function main() { fixture.detectChanges(); engine.flush(); - expect(count).toEqual(0); + expect(count).toEqual(5); }); it('should allow for queried items to restore their styling back to the original state via animate(time, "*")',