diff --git a/packages/animations/browser/src/render/transition_animation_engine.ts b/packages/animations/browser/src/render/transition_animation_engine.ts index 21286b13f9..8cd6f715ae 100644 --- a/packages/animations/browser/src/render/transition_animation_engine.ts +++ b/packages/animations/browser/src/render/transition_animation_engine.ts @@ -18,6 +18,9 @@ import {ENTER_CLASSNAME, LEAVE_CLASSNAME, NG_ANIMATING_CLASSNAME, NG_ANIMATING_S import {AnimationDriver} from './animation_driver'; import {getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared'; +const QUEUED_CLASSNAME = 'ng-animate-queued'; +const QUEUED_SELECTOR = '.ng-animate-queued'; + const EMPTY_PLAYER_ARRAY: TransitionAnimationPlayer[] = []; const NULL_REMOVAL_STATE: ElementAnimationState = { namespaceId: '', @@ -235,12 +238,11 @@ export class AnimationTransitionNamespace { {element, triggerName, transition, fromState, toState, player, isFallbackTransition}); if (!isFallbackTransition) { - addClass(element, NG_ANIMATING_CLASSNAME); + addClass(element, QUEUED_CLASSNAME); + player.onStart(() => { removeClass(element, QUEUED_CLASSNAME); }); } player.onDone(() => { - removeClass(element, NG_ANIMATING_CLASSNAME); - let index = this.players.indexOf(player); if (index >= 0) { this.players.splice(index, 1); diff --git a/packages/core/test/animation/animation_query_integration_spec.ts b/packages/core/test/animation/animation_query_integration_spec.ts index aa358d972f..bb5ba44987 100644 --- a/packages/core/test/animation/animation_query_integration_spec.ts +++ b/packages/core/test/animation/animation_query_integration_spec.ts @@ -39,7 +39,7 @@ export function main() { }); describe('query()', () => { - it('should be able to query all animation triggers via `@*`', () => { + it('should be able to query all elements that contain animation triggers via @*', () => { @Component({ selector: 'ani-cmp', template: ` @@ -56,30 +56,40 @@ export function main() { 'parent', [ transition( - '* => *', + '* => go', [ query( - '@*:animating', + '@*', [ - animate(1000, style({background: 'red'})), + style({ backgroundColor: 'blue' }), + animate(1000, style({backgroundColor: 'red'})), ]), ]), ]), trigger( 'a', [ - transition('* => *', []), + transition('* => 1', [ + animate(1000, style({ opacity: 0 })) + ]), ]), trigger( 'b', [ - transition('* => *', []), + transition('* => 1', [ + animate(1000, style({ opacity: 0 })), + query('.b-inner', [ + animate(1000, style({ opacity: 0 })) + ]), + ]), ]), trigger( 'c', [ - transition('* => *', []), - ]) + transition('* => 1', [ + animate(1000, style({ opacity: 0 })) + ]), + ]), ] }) class Cmp { @@ -90,23 +100,117 @@ export function main() { TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); const fixture = TestBed.createComponent(Cmp); const cmp = fixture.componentInstance; - cmp.exp0 = 1; + cmp.exp0 = 'go'; + fixture.detectChanges(); + + let players = getLog(); + expect(players.length).toEqual(3); // a,b,c + resetLog(); + + const [p1, p2, p3] = players; + expect(p1.element.classList.contains('a')).toBeTruthy(); + expect(p2.element.classList.contains('b')).toBeTruthy(); + expect(p3.element.classList.contains('c')).toBeTruthy(); + }); + + it('should be able to query currently animating elements via :animating', () => { + @Component({ + selector: 'ani-cmp', + template: ` +
+
+
+
+
+
+
+ `, + animations: [ + trigger( + 'parent', + [ + transition( + '* => go', + [ + query( + ':animating', + [ + style({ backgroundColor: 'blue' }), + animate(1000, style({backgroundColor: 'red'})), + ]), + ]), + ]), + trigger( + 'a', + [ + transition('* => 1', [ + animate(1000, style({ opacity: 0 })) + ]), + ]), + trigger( + 'b', + [ + transition('* => 1', [ + animate(1000, style({ opacity: 0 })), + query('.b-inner', [ + animate(1000, style({ opacity: 0 })) + ]), + ]), + ]), + trigger( + 'c', + [ + transition('* => 1', [ + animate(1000, style({ opacity: 0 })) + ]), + ]), + ] + }) + class Cmp { + public exp0: any; + public exp1: any; + public exp2: any; + public exp3: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp0 = ''; cmp.exp1 = 1; cmp.exp2 = 1; + // note that exp3 is skipped here fixture.detectChanges(); - engine.flush(); - const players = getLog(); + let players = getLog(); + expect(players.length).toEqual(3); // a,b,b-inner and not c + resetLog(); + + cmp.exp0 = 'go'; + fixture.detectChanges(); + + const expectedKeyframes = [ + {backgroundColor: 'blue', offset: 0}, + {backgroundColor: 'red', offset: 1}, + ]; + + players = getLog(); expect(players.length).toEqual(3); const [p1, p2, p3] = players; expect(p1.element.classList.contains('a')).toBeTruthy(); + expect(p1.keyframes).toEqual(expectedKeyframes); + expect(p2.element.classList.contains('b')).toBeTruthy(); - expect(p3.element.classList.contains('c')).toBeTruthy(); + expect(p2.keyframes).toEqual(expectedKeyframes); + + expect(p3.element.classList.contains('b-inner')).toBeTruthy(); + expect(p3.keyframes).toEqual(expectedKeyframes); }); it('should be able to query triggers directly by name', () => {