fix(animations): ensure `:animating` queries collect previous animation elements properly

This commit is contained in:
Matias Niemelä 2017-07-06 10:39:22 -07:00 committed by Jason Aden
parent f85b543cc1
commit 3203639d7d
2 changed files with 122 additions and 16 deletions

View File

@ -18,6 +18,9 @@ import {ENTER_CLASSNAME, LEAVE_CLASSNAME, NG_ANIMATING_CLASSNAME, NG_ANIMATING_S
import {AnimationDriver} from './animation_driver';
import {getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared';
const QUEUED_CLASSNAME = 'ng-animate-queued';
const QUEUED_SELECTOR = '.ng-animate-queued';
const EMPTY_PLAYER_ARRAY: TransitionAnimationPlayer[] = [];
const NULL_REMOVAL_STATE: ElementAnimationState = {
namespaceId: '',
@ -235,12 +238,11 @@ export class AnimationTransitionNamespace {
{element, triggerName, transition, fromState, toState, player, isFallbackTransition});
if (!isFallbackTransition) {
addClass(element, NG_ANIMATING_CLASSNAME);
addClass(element, QUEUED_CLASSNAME);
player.onStart(() => { removeClass(element, QUEUED_CLASSNAME); });
}
player.onDone(() => {
removeClass(element, NG_ANIMATING_CLASSNAME);
let index = this.players.indexOf(player);
if (index >= 0) {
this.players.splice(index, 1);

View File

@ -39,7 +39,7 @@ export function main() {
});
describe('query()', () => {
it('should be able to query all animation triggers via `@*`', () => {
it('should be able to query all elements that contain animation triggers via @*', () => {
@Component({
selector: 'ani-cmp',
template: `
@ -56,30 +56,40 @@ export function main() {
'parent',
[
transition(
'* => *',
'* => go',
[
query(
'@*:animating',
'@*',
[
animate(1000, style({background: 'red'})),
style({ backgroundColor: 'blue' }),
animate(1000, style({backgroundColor: 'red'})),
]),
]),
]),
trigger(
'a',
[
transition('* => *', []),
transition('* => 1', [
animate(1000, style({ opacity: 0 }))
]),
]),
trigger(
'b',
[
transition('* => *', []),
transition('* => 1', [
animate(1000, style({ opacity: 0 })),
query('.b-inner', [
animate(1000, style({ opacity: 0 }))
]),
]),
]),
trigger(
'c',
[
transition('* => *', []),
])
transition('* => 1', [
animate(1000, style({ opacity: 0 }))
]),
]),
]
})
class Cmp {
@ -90,23 +100,117 @@ export function main() {
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.get(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp0 = 1;
cmp.exp0 = 'go';
fixture.detectChanges();
let players = getLog();
expect(players.length).toEqual(3); // a,b,c
resetLog();
const [p1, p2, p3] = players;
expect(p1.element.classList.contains('a')).toBeTruthy();
expect(p2.element.classList.contains('b')).toBeTruthy();
expect(p3.element.classList.contains('c')).toBeTruthy();
});
it('should be able to query currently animating elements via :animating', () => {
@Component({
selector: 'ani-cmp',
template: `
<div [@parent]="exp0">
<div class="a" [@a]="exp1"></div>
<div class="b" [@b]="exp2">
<div class="b-inner"></div>
</div>
<div class="c" [@c]="exp3"></div>
</div>
`,
animations: [
trigger(
'parent',
[
transition(
'* => go',
[
query(
':animating',
[
style({ backgroundColor: 'blue' }),
animate(1000, style({backgroundColor: 'red'})),
]),
]),
]),
trigger(
'a',
[
transition('* => 1', [
animate(1000, style({ opacity: 0 }))
]),
]),
trigger(
'b',
[
transition('* => 1', [
animate(1000, style({ opacity: 0 })),
query('.b-inner', [
animate(1000, style({ opacity: 0 }))
]),
]),
]),
trigger(
'c',
[
transition('* => 1', [
animate(1000, style({ opacity: 0 }))
]),
]),
]
})
class Cmp {
public exp0: any;
public exp1: any;
public exp2: any;
public exp3: any;
}
TestBed.configureTestingModule({declarations: [Cmp]});
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp0 = '';
cmp.exp1 = 1;
cmp.exp2 = 1;
// note that exp3 is skipped here
fixture.detectChanges();
engine.flush();
const players = getLog();
let players = getLog();
expect(players.length).toEqual(3); // a,b,b-inner and not c
resetLog();
cmp.exp0 = 'go';
fixture.detectChanges();
const expectedKeyframes = [
{backgroundColor: 'blue', offset: 0},
{backgroundColor: 'red', offset: 1},
];
players = getLog();
expect(players.length).toEqual(3);
const [p1, p2, p3] = players;
expect(p1.element.classList.contains('a')).toBeTruthy();
expect(p1.keyframes).toEqual(expectedKeyframes);
expect(p2.element.classList.contains('b')).toBeTruthy();
expect(p3.element.classList.contains('c')).toBeTruthy();
expect(p2.keyframes).toEqual(expectedKeyframes);
expect(p3.element.classList.contains('b-inner')).toBeTruthy();
expect(p3.keyframes).toEqual(expectedKeyframes);
});
it('should be able to query triggers directly by name', () => {