@@ -20,7 +20,16 @@ import {
2020 getClassListFromValue ,
2121} from '../../animation/element_removal_registry' ;
2222import { getLView , getCurrentTNode , getTView , getAnimationElementRemovalRegistry } from '../state' ;
23- import { RENDERER , INJECTOR , CONTEXT , FLAGS , LViewFlags , LView , TView } from '../interfaces/view' ;
23+ import {
24+ RENDERER ,
25+ INJECTOR ,
26+ CONTEXT ,
27+ FLAGS ,
28+ LViewFlags ,
29+ LView ,
30+ TView ,
31+ DECLARATION_LCONTAINER ,
32+ } from '../interfaces/view' ;
2433import { RuntimeError , RuntimeErrorCode } from '../../errors' ;
2534import { getNativeByTNode , storeCleanupWithContext } from '../util/view_utils' ;
2635import { performanceMarkFeature } from '../../util/performance' ;
@@ -30,6 +39,7 @@ import {NgZone} from '../../zone';
3039import { assertDefined } from '../../util/assert' ;
3140import { determineLongestAnimation , LongestAnimation } from '../../animation/longest_animation' ;
3241import { TNode } from '../interfaces/node' ;
42+ import { getBeforeNodeForView } from '../node_manipulation' ;
3343
3444const DEFAULT_ANIMATIONS_DISABLED = false ;
3545const areAnimationSupported =
@@ -101,15 +111,25 @@ function clearLeavingNodes(tNode: TNode, el: HTMLElement): void {
101111
102112/**
103113 * In the case that we have an existing node that's animating away, like when
104- * an `@if` toggles quickly or `@for` adds and removes elements quickly, we
105- * need to end the animation for the former node and remove it right away to
106- * prevent duplicate nodes showing up.
114+ * an `@if` toggles quickly, we need to end the animation for the former node
115+ * and remove it right away to prevent duplicate nodes showing up.
107116 */
108- function cancelLeavingNodes ( tNode : TNode , el : HTMLElement ) : void {
109- leavingNodes
110- . get ( tNode )
111- ?. pop ( )
112- ?. dispatchEvent ( new CustomEvent ( 'animationend' , { detail : { cancel : true } } ) ) ;
117+ function cancelLeavingNodes ( tNode : TNode , lView : LView ) : void {
118+ const leavingEl = leavingNodes . get ( tNode ) ?. shift ( ) ;
119+ const lContainer = lView [ DECLARATION_LCONTAINER ] ;
120+ if ( lContainer ) {
121+ // this is the insertion point for the new TNode element.
122+ // it will be inserted before the declaring containers anchor.
123+ const beforeNode = getBeforeNodeForView ( tNode . index , lContainer ) ;
124+ // here we need to check the previous sibling of that anchor
125+ const previousNode = beforeNode ?. previousSibling ;
126+ // We really only want to cancel animations if the leaving node is the
127+ // same as the node before where the new node will be inserted. This is
128+ // the control flow scenario where an if was toggled.
129+ if ( leavingEl && previousNode && leavingEl === previousNode ) {
130+ leavingEl . dispatchEvent ( new CustomEvent ( 'animationend' , { detail : { cancel : true } } ) ) ;
131+ }
132+ }
113133}
114134
115135function trackLeavingNodes ( tNode : TNode , el : HTMLElement ) : void {
@@ -178,6 +198,8 @@ export function ɵɵanimateEnter(value: string | Function): typeof ɵɵanimateEn
178198 cleanupFns . push ( renderer . listen ( nativeElement , 'transitionstart' , handleAnimationStart ) ) ;
179199 } ) ;
180200
201+ cancelLeavingNodes ( tNode , lView ) ;
202+
181203 trackEnterClasses ( nativeElement , activeClasses , cleanupFns ) ;
182204
183205 for ( const klass of activeClasses ) {
@@ -188,12 +210,6 @@ export function ɵɵanimateEnter(value: string | Function): typeof ɵɵanimateEn
188210 // preventing an animation via selector specificity.
189211 ngZone . runOutsideAngular ( ( ) => {
190212 requestAnimationFrame ( ( ) => {
191- // In the case that we have an existing node that's animating away, like when
192- // an `@if` toggles quickly or `@for` adds and removes elements quickly, we
193- // need to end the animation for the former node and remove it right away to
194- // prevent duplicate nodes showing up.
195- cancelLeavingNodes ( tNode , nativeElement ) ;
196-
197213 determineLongestAnimation ( nativeElement , longestAnimations , areAnimationSupported ) ;
198214 if ( ! longestAnimations . has ( nativeElement ) ) {
199215 for ( const klass of activeClasses ) {
@@ -253,11 +269,8 @@ export function ɵɵanimateEnterListener(value: AnimationFunction): typeof ɵɵa
253269
254270 const tNode = getCurrentTNode ( ) ! ;
255271 const nativeElement = getNativeByTNode ( tNode , lView ) as HTMLElement ;
256- // In the case that we have an existing node that's animating away, like when
257- // an `@if` toggles quickly or `@for` adds and removes elements quickly, we
258- // need to end the animation for the former node and remove it right away to
259- // prevent duplicate nodes showing up.
260- cancelLeavingNodes ( tNode , nativeElement ) ;
272+
273+ cancelLeavingNodes ( tNode , lView ) ;
261274
262275 value . call ( lView [ CONTEXT ] , { target : nativeElement , animationComplete : noOpAnimationComplete } ) ;
263276
0 commit comments