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:
Matias Niemelä 2016-11-04 15:15:27 -07:00 committed by vikerman
parent 2a3f4d7b17
commit 383f23b578
2 changed files with 43 additions and 2 deletions

View File

@ -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();

View File

@ -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, {