Skip to content

Commit 05f5e8a

Browse files
dario-piotrowiczalxhub
authored andcommitted
fix(animations): fix stagger timing not handling params (angular#47208)
prior to this change the stagger timing was being built during the ast building instead of dynamically when visiting the stagger animation, thus it could not handle params correctly, this change makes it so that during ast building a timing ast is built instead and that ast is used dynammically to build animations which can handle params correctly resolves angular#19786 PR Close angular#47208
1 parent 876ba77 commit 05f5e8a

File tree

4 files changed

+109
-4
lines changed

4 files changed

+109
-4
lines changed

packages/animations/browser/src/dsl/animation_ast_builder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
473473
}
474474
const timings = metadata.timings === 'full' ?
475475
{duration: 0, delay: 0, easing: 'full'} :
476-
resolveTiming(metadata.timings, context.errors, true);
476+
constructTimingAst(metadata.timings, context.errors);
477477

478478
return {
479479
type: AnimationMetadataType.Stagger,

packages/animations/browser/src/dsl/animation_timeline_builder.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,12 +278,14 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
278278
context.previousNode = ast;
279279
}
280280

281-
private _visitTiming(ast: TimingAst, context: AnimationTimelineContext): AnimateTimings {
281+
private _visitTiming(
282+
ast: TimingAst, context: AnimationTimelineContext,
283+
allowNegativeValues = false): AnimateTimings {
282284
if ((ast as DynamicTimingAst).dynamic) {
283285
const strValue = (ast as DynamicTimingAst).strValue;
284286
const timingValue =
285287
context.params ? interpolateParams(strValue, context.params, context.errors) : strValue;
286-
return resolveTiming(timingValue, context.errors);
288+
return resolveTiming(timingValue, context.errors, allowNegativeValues);
287289
} else {
288290
return {duration: ast.duration, delay: ast.delay, easing: ast.easing};
289291
}
@@ -413,7 +415,8 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
413415
visitStagger(ast: StaggerAst, context: AnimationTimelineContext) {
414416
const parentContext = context.parentContext!;
415417
const tl = context.currentTimeline;
416-
const timings = ast.timings;
418+
const timings = this._visitTiming(ast.timings, context, true);
419+
417420
const duration = Math.abs(timings.duration);
418421
const maxTime = duration * (context.currentQueryTotal - 1);
419422
let delay = duration * context.currentQueryIndex;

packages/core/test/animation/animation_query_integration_spec.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,105 @@ describe('animation query tests', function() {
742742
expect(p5.delay).toEqual(6000);
743743
});
744744

745+
it(`should handle params used in the stagger's timing argument`, () => {
746+
@Component({
747+
selector: 'ani-cmp',
748+
template: `
749+
<div [@myAnimation]="exp">
750+
<div *ngFor="let item of items" class="item">
751+
{{ item }}
752+
</div>
753+
</div>
754+
`,
755+
animations: [
756+
trigger('myAnimation', [
757+
transition('* => go', [
758+
query('.item', [
759+
stagger('{{staggerDelay}}ms',[
760+
style({opacity: 0}), animate(1000, style({opacity: .5})),
761+
animate(500, style({opacity: 1}))
762+
])
763+
])
764+
], {params: { staggerDelay: '1111' }})
765+
])
766+
]
767+
})
768+
class Cmp {
769+
public exp: any;
770+
public items: any[] = [0, 1, 2, 3, 4];
771+
}
772+
773+
TestBed.configureTestingModule({declarations: [Cmp]});
774+
775+
const engine = TestBed.inject(ɵAnimationEngine);
776+
const fixture = TestBed.createComponent(Cmp);
777+
const cmp = fixture.componentInstance;
778+
779+
cmp.exp = 'go';
780+
fixture.detectChanges();
781+
engine.flush();
782+
783+
const players = getLog();
784+
expect(players.length).toEqual(5);
785+
786+
const [p1, p2, p3, p4, p5] = players;
787+
expect(p1.delay).toEqual(0);
788+
expect(p2.delay).toEqual(1111);
789+
expect(p3.delay).toEqual(2222);
790+
expect(p4.delay).toEqual(3333);
791+
expect(p5.delay).toEqual(4444);
792+
});
793+
794+
it(`should handle params used in the stagger's timing argument producing a negative value`,
795+
() => {
796+
@Component({
797+
selector: 'ani-cmp',
798+
template: `
799+
<div [@myAnimation]="exp">
800+
<div *ngFor="let item of items" class="item">
801+
{{ item }}
802+
</div>
803+
</div>
804+
`,
805+
animations: [
806+
trigger('myAnimation', [
807+
transition('* => go', [
808+
query('.item', [
809+
stagger('{{staggerDelay}}ms',[
810+
style({opacity: 0}), animate(1000, style({opacity: .5})),
811+
animate(500, style({opacity: 1}))
812+
])
813+
])
814+
], {params: { staggerDelay: -1111 }})
815+
])
816+
]
817+
})
818+
class Cmp {
819+
public exp: any;
820+
public items: any[] = [0, 1, 2, 3, 4];
821+
}
822+
823+
TestBed.configureTestingModule({declarations: [Cmp]});
824+
825+
const engine = TestBed.inject(ɵAnimationEngine);
826+
const fixture = TestBed.createComponent(Cmp);
827+
const cmp = fixture.componentInstance;
828+
829+
cmp.exp = 'go';
830+
fixture.detectChanges();
831+
engine.flush();
832+
833+
const players = getLog();
834+
expect(players.length).toEqual(5);
835+
836+
const [p1, p2, p3, p4, p5] = players;
837+
expect(p5.delay).toEqual(0);
838+
expect(p4.delay).toEqual(1111);
839+
expect(p3.delay).toEqual(2222);
840+
expect(p2.delay).toEqual(3333);
841+
expect(p1.delay).toEqual(4444);
842+
});
843+
745844
it('should persist inner sub trigger styles once their animation is complete', () => {
746845
@Component({
747846
selector: 'ani-cmp',

packages/core/test/bundling/animations/bundle.golden_symbols.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,9 @@
647647
{
648648
"name": "connectableObservableDescriptor"
649649
},
650+
{
651+
"name": "constructTimingAst"
652+
},
650653
{
651654
"name": "containsElement"
652655
},

0 commit comments

Comments
 (0)