fix(animations): always trigger animations after the change detection check (#12713)
This patch ensures that animations are run outside of change detection thus allowing for start and done callbacks to modify application data without causing a cycle loop. Closes #12713
This commit is contained in:
parent
2a3f4d7b17
commit
383f23b578
|
@ -17,6 +17,15 @@ export function queueAnimation(player: AnimationPlayer) {
|
|||
|
||||
/** @internal */
|
||||
export function triggerQueuedAnimations() {
|
||||
// this code is wrapped into a single promise such that the
|
||||
// onStart and onDone player callbacks are triggered outside
|
||||
// of the digest cycle of animations
|
||||
if (_queuedAnimations.length) {
|
||||
Promise.resolve(null).then(_triggerAnimations);
|
||||
}
|
||||
}
|
||||
|
||||
function _triggerAnimations() {
|
||||
for (var i = 0; i < _queuedAnimations.length; i++) {
|
||||
var player = _queuedAnimations[i];
|
||||
player.play();
|
||||
|
|
|
@ -1151,7 +1151,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||
|
||||
describe('animation output events', () => {
|
||||
it('should fire the associated animation output expression when the animation starts even if no animation is fired',
|
||||
() => {
|
||||
fakeAsync(() => {
|
||||
TestBed.overrideComponent(DummyIfCmp, {
|
||||
set: {
|
||||
template: `
|
||||
|
@ -1175,16 +1175,18 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||
|
||||
cmp.exp = 'one';
|
||||
fixture.detectChanges();
|
||||
flushMicrotasks();
|
||||
|
||||
expect(calls).toEqual(1);
|
||||
expect(isAnimationRunning).toEqual(false);
|
||||
|
||||
cmp.exp = 'two';
|
||||
fixture.detectChanges();
|
||||
flushMicrotasks();
|
||||
|
||||
expect(calls).toEqual(2);
|
||||
expect(isAnimationRunning).toEqual(true);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fire the associated animation output expression when the animation ends even if no animation is fired',
|
||||
fakeAsync(() => {
|
||||
|
@ -1296,6 +1298,36 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||
expect(eventData2.totalTime).toEqual(0);
|
||||
}));
|
||||
|
||||
it('should successfully update the component view when an animation start callback is fired',
|
||||
fakeAsync(() => {
|
||||
TestBed.overrideComponent(DummyIfCmp, {
|
||||
set: {
|
||||
template: `
|
||||
<div [@trigger]="exp" (@trigger.start)="exp2='look at me'">{{ exp2 }}</div>
|
||||
`,
|
||||
animations: [
|
||||
trigger(
|
||||
'trigger',
|
||||
[transition(
|
||||
'* => *',
|
||||
[animate('1s 750ms', style({})), animate('2000ms 0ms', style({}))])]),
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
let fixture = TestBed.createComponent(DummyIfCmp);
|
||||
var cmp = fixture.componentInstance;
|
||||
cmp.exp2 = 'ignore me';
|
||||
cmp.exp = 'one';
|
||||
|
||||
fixture.detectChanges();
|
||||
flushMicrotasks();
|
||||
fixture.detectChanges();
|
||||
|
||||
var container = fixture.nativeElement;
|
||||
expect(getDOM().getInnerHTML(container)).toContain('look at me');
|
||||
}));
|
||||
|
||||
it('should throw an error if an animation output is referenced is not defined within the component',
|
||||
() => {
|
||||
TestBed.overrideComponent(DummyIfCmp, {
|
||||
|
|
Loading…
Reference in New Issue