Skip to content

Commit

Permalink
fix(animations): reset the start and done fns on player reset (#46364)
Browse files Browse the repository at this point in the history
in the animation players, make sure than upon reset the
_onStartFns and _onDoneFns are also re-applied so that
they can be called again after resetting the animation

also set the noop animation player's _finished to false
when the player resets (needed to make sure that the _onDoneFns
get called)

resolves #26630

PR Close #46364
  • Loading branch information
dario-piotrowicz authored and AndrewKushnir committed Jun 21, 2022
1 parent 79a973a commit 3dd7bb3
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 1 deletion.
2 changes: 1 addition & 1 deletion goldens/size-tracking/aio-payloads.json
Expand Up @@ -12,7 +12,7 @@
"aio-local": {
"uncompressed": {
"runtime": 4325,
"main": 456412,
"main": 456957,
"polyfills": 33922,
"styles": 72829,
"light-theme": 78276,
Expand Down
Expand Up @@ -24,6 +24,12 @@ export class WebAnimationsPlayer implements AnimationPlayer {
private _destroyed = false;
private _finalKeyframe?: ɵStyleDataMap;

// the following original fns are persistent copies of the _onStartFns and _onDoneFns
// and are used to reset the fns to their original values upon reset()
// (since the _onStartFns and _onDoneFns get deleted after they are called)
private _originalOnDoneFns: Function[] = [];
private _originalOnStartFns: Function[] = [];

// TODO(issue/24571): remove '!'.
public readonly domPlayer!: DOMAnimation;
public time = 0;
Expand Down Expand Up @@ -89,10 +95,12 @@ export class WebAnimationsPlayer implements AnimationPlayer {
}

onStart(fn: () => void): void {
this._originalOnStartFns.push(fn);
this._onStartFns.push(fn);
}

onDone(fn: () => void): void {
this._originalOnDoneFns.push(fn);
this._onDoneFns.push(fn);
}

Expand Down Expand Up @@ -132,6 +140,8 @@ export class WebAnimationsPlayer implements AnimationPlayer {
this._destroyed = false;
this._finished = false;
this._started = false;
this._onStartFns = this._originalOnStartFns;
this._onDoneFns = this._originalOnDoneFns;
}

private _resetDomPlayerState() {
Expand Down
7 changes: 7 additions & 0 deletions packages/animations/src/players/animation_player.ts
Expand Up @@ -123,6 +123,8 @@ export class NoopAnimationPlayer implements AnimationPlayer {
private _onDoneFns: Function[] = [];
private _onStartFns: Function[] = [];
private _onDestroyFns: Function[] = [];
private _originalOnDoneFns: Function[] = [];
private _originalOnStartFns: Function[] = [];
private _started = false;
private _destroyed = false;
private _finished = false;
Expand All @@ -140,9 +142,11 @@ export class NoopAnimationPlayer implements AnimationPlayer {
}
}
onStart(fn: () => void): void {
this._originalOnStartFns.push(fn);
this._onStartFns.push(fn);
}
onDone(fn: () => void): void {
this._originalOnDoneFns.push(fn);
this._onDoneFns.push(fn);
}
onDestroy(fn: () => void): void {
Expand Down Expand Up @@ -188,6 +192,9 @@ export class NoopAnimationPlayer implements AnimationPlayer {
}
reset(): void {
this._started = false;
this._finished = false;
this._onStartFns = this._originalOnStartFns;
this._onDoneFns = this._originalOnDoneFns;
}
setPosition(position: number): void {
this._position = this.totalTime ? position * this.totalTime : 1;
Expand Down
Expand Up @@ -45,6 +45,75 @@ import {NoopAnimationsModule, ɵBrowserAnimationBuilder as BrowserAnimationBuild
expect(cmp.builder instanceof BrowserAnimationBuilder).toBeTruthy();
});

it('should listen on start and done on the animation builder\'s player after it has been reset',
fakeAsync(() => {
@Component({
selector: 'ani-cmp',
template: '...',
})
class Cmp {
@ViewChild('target') public target: any;

constructor(public builder: AnimationBuilder) {}

build() {
const definition =
this.builder.build([style({opacity: 0}), animate(1000, style({opacity: 1}))]);

return definition.create(this.target);
}
}

TestBed.configureTestingModule({declarations: [Cmp]});

const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
fixture.detectChanges();

const player = cmp.build();

let startedCount = 0;
player.onStart(() => startedCount++);

let finishedCount = 0;
player.onDone(() => finishedCount++);

player.init();
flushMicrotasks();
expect(startedCount).toEqual(0);
expect(finishedCount).toEqual(0);

player.play();
flushMicrotasks();
expect(startedCount).toEqual(1);
expect(finishedCount).toEqual(0);

player.finish();
flushMicrotasks();
expect(startedCount).toEqual(1);
expect(finishedCount).toEqual(1);

player.play();
player.finish();
flushMicrotasks();
expect(startedCount).toEqual(1);
expect(finishedCount).toEqual(1);

[0, 1, 2, 3].forEach(i => {
player.reset();

player.play();
flushMicrotasks();
expect(startedCount).toEqual(i + 2);
expect(finishedCount).toEqual(i + 1);

player.finish();
flushMicrotasks();
expect(startedCount).toEqual(i + 2);
expect(finishedCount).toEqual(i + 2);
});
}));

it('should listen on start and done on the animation builder\'s player', fakeAsync(() => {
@Component({
selector: 'ani-cmp',
Expand Down

0 comments on commit 3dd7bb3

Please sign in to comment.