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 */
|
/** @internal */
|
||||||
export function triggerQueuedAnimations() {
|
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++) {
|
for (var i = 0; i < _queuedAnimations.length; i++) {
|
||||||
var player = _queuedAnimations[i];
|
var player = _queuedAnimations[i];
|
||||||
player.play();
|
player.play();
|
||||||
|
|
|
@ -1151,7 +1151,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||||
|
|
||||||
describe('animation output events', () => {
|
describe('animation output events', () => {
|
||||||
it('should fire the associated animation output expression when the animation starts even if no animation is fired',
|
it('should fire the associated animation output expression when the animation starts even if no animation is fired',
|
||||||
() => {
|
fakeAsync(() => {
|
||||||
TestBed.overrideComponent(DummyIfCmp, {
|
TestBed.overrideComponent(DummyIfCmp, {
|
||||||
set: {
|
set: {
|
||||||
template: `
|
template: `
|
||||||
|
@ -1175,16 +1175,18 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||||
|
|
||||||
cmp.exp = 'one';
|
cmp.exp = 'one';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
flushMicrotasks();
|
||||||
|
|
||||||
expect(calls).toEqual(1);
|
expect(calls).toEqual(1);
|
||||||
expect(isAnimationRunning).toEqual(false);
|
expect(isAnimationRunning).toEqual(false);
|
||||||
|
|
||||||
cmp.exp = 'two';
|
cmp.exp = 'two';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
flushMicrotasks();
|
||||||
|
|
||||||
expect(calls).toEqual(2);
|
expect(calls).toEqual(2);
|
||||||
expect(isAnimationRunning).toEqual(true);
|
expect(isAnimationRunning).toEqual(true);
|
||||||
});
|
}));
|
||||||
|
|
||||||
it('should fire the associated animation output expression when the animation ends even if no animation is fired',
|
it('should fire the associated animation output expression when the animation ends even if no animation is fired',
|
||||||
fakeAsync(() => {
|
fakeAsync(() => {
|
||||||
|
@ -1296,6 +1298,36 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||||
expect(eventData2.totalTime).toEqual(0);
|
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',
|
it('should throw an error if an animation output is referenced is not defined within the component',
|
||||||
() => {
|
() => {
|
||||||
TestBed.overrideComponent(DummyIfCmp, {
|
TestBed.overrideComponent(DummyIfCmp, {
|
||||||
|
|
Loading…
Reference in New Issue