diff --git a/packages/animations/browser/src/dsl/animation_timeline_builder.ts b/packages/animations/browser/src/dsl/animation_timeline_builder.ts index b4cf46b4dc7d4..e4e9b90bddea2 100644 --- a/packages/animations/browser/src/dsl/animation_timeline_builder.ts +++ b/packages/animations/browser/src/dsl/animation_timeline_builder.ts @@ -183,32 +183,25 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor { visitAnimateRef(ast: AnimateRefAst, context: AnimationTimelineContext): any { const innerContext = context.createSubContext(ast.options); innerContext.transformIntoNewTimeline(); - this._applyAnimateRefDelay(ast.animation, context, innerContext); + this._applyAnimationRefDelays([ast.options, ast.animation.options], context, innerContext); this.visitReference(ast.animation, innerContext); context.transformIntoNewTimeline(innerContext.currentTimeline.currentTime); context.previousNode = ast; } - private _applyAnimateRefDelay( - animation: ReferenceAst, context: AnimationTimelineContext, + private _applyAnimationRefDelays( + animationsRefsOptions: (AnimationOptions|null)[], context: AnimationTimelineContext, innerContext: AnimationTimelineContext) { - const animationDelay = animation.options?.delay; - - if (!animationDelay) { - return; - } - - let animationDelayValue: number; - - if (typeof animationDelay === 'string') { - const interpolatedDelay = - interpolateParams(animationDelay, animation.options?.params ?? {}, context.errors); - animationDelayValue = resolveTimingValue(interpolatedDelay); - } else { - animationDelayValue = animationDelay; + for (const animationRefOptions of animationsRefsOptions) { + const animationDelay = animationRefOptions?.delay; + if (animationDelay) { + const animationDelayValue = typeof animationDelay === 'number' ? + animationDelay : + resolveTimingValue(interpolateParams( + animationDelay, animationRefOptions?.params ?? {}, context.errors)); + innerContext.delayNextStep(animationDelayValue); + } } - - innerContext.delayNextStep(animationDelayValue); } private _visitSubInstructions( diff --git a/packages/core/test/animation/animation_integration_spec.ts b/packages/core/test/animation/animation_integration_spec.ts index be15eafcf5054..aba0ad4119a49 100644 --- a/packages/core/test/animation/animation_integration_spec.ts +++ b/packages/core/test/animation/animation_integration_spec.ts @@ -3923,13 +3923,57 @@ describe('animation tests', function() { ]); }); - it('should combine the delay specified in the animation with that of the caller', () => { + it('should apply the delay specified in the useAnimation call', () => { + const animationMetaData = animation([ + style({color: 'red'}), + animate(550, style({color: 'green'})), + ]); + + @Component({ + selector: 'cmp', + template: ` +
+
+ `, + animations: [ + trigger('anim', [transition( + ':enter', + useAnimation(animationMetaData, {delay: 1500}), + )]), + ] + }) + class Cmp { + exp: boolean = false; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = true; + + fixture.detectChanges(); + engine.flush(); + + const players = getLog(); + expect(players.length).toEqual(1); + const [player] = players; + expect(player.delay).toEqual(1500); + expect(player.duration).toEqual(550); + expect(player.keyframes).toEqual([ + new Map([['color', 'red'], ['offset', 0]]), + new Map([['color', 'green'], ['offset', 1]]), + ]); + }); + + it('should apply the delay specified in the useAnimation call using params', () => { const animationMetaData = animation( [ style({color: 'red'}), - animate(500, style({color: 'green'})), + animate(700, style({color: 'green'})), ], - {delay: 2000}); + ); @Component({ selector: 'cmp', @@ -3938,7 +3982,13 @@ describe('animation tests', function() { `, animations: [ - trigger('anim', [transition(':enter', useAnimation(animationMetaData), {delay: 750})]), + trigger('anim', [transition( + ':enter', + useAnimation(animationMetaData, { + delay: '{{useAnimationDelay}}ms', + params: {useAnimationDelay: 7500} + }), + )]), ] }) class Cmp { @@ -3958,13 +4008,59 @@ describe('animation tests', function() { const players = getLog(); expect(players.length).toEqual(1); const [player] = players; - expect(player.delay).toEqual(2750); - expect(player.duration).toEqual(500); + expect(player.delay).toEqual(7500); + expect(player.duration).toEqual(700); expect(player.keyframes).toEqual([ new Map([['color', 'red'], ['offset', 0]]), new Map([['color', 'green'], ['offset', 1]]), ]); }); + + it('should combine the delays specified in the animation and the useAnimation with that of the caller', + () => { + const animationMetaData = animation( + [ + style({color: 'red'}), + animate(567, style({color: 'green'})), + ], + {delay: 1000}); + + @Component({ + selector: 'cmp', + template: ` +
+
+ `, + animations: [ + trigger('anim', [transition( + ':enter', useAnimation(animationMetaData, {delay: 34}), + {delay: 200})]), + ] + }) + class Cmp { + exp: boolean = false; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = true; + + fixture.detectChanges(); + engine.flush(); + + const players = getLog(); + expect(players.length).toEqual(1); + const [player] = players; + expect(player.delay).toEqual(1234); + expect(player.duration).toEqual(567); + expect(player.keyframes).toEqual([ + new Map([['color', 'red'], ['offset', 0]]), + new Map([['color', 'green'], ['offset', 1]]), + ]); + }); }); it('should combine multiple errors together into one exception when an animation fails to be built',