fix(animations): stringify boolean values as `1` and `0` (#15311)

Closes #15247
Closes #15311

PR Close #15311
This commit is contained in:
Matias Niemelä 2017-03-20 10:35:02 -07:00 committed by Miško Hevery
parent 764e90f9bb
commit 94da80148e
2 changed files with 55 additions and 4 deletions

View File

@ -31,6 +31,7 @@ export interface TriggerListenerTuple {
const MARKED_FOR_ANIMATION_CLASSNAME = 'ng-animating';
const MARKED_FOR_ANIMATION_SELECTOR = '.ng-animating';
const MARKED_FOR_REMOVAL = '$$ngRemove';
const VOID_STATE = 'void';
export class DomAnimationEngine {
private _flaggedInserts = new Set<any>();
@ -84,7 +85,7 @@ export class DomAnimationEngine {
const possibleTriggers = Object.keys(lookupRef);
const hasRemoval = possibleTriggers.some(triggerName => {
const oldValue = lookupRef[triggerName];
const instruction = this._triggers[triggerName].matchTransition(oldValue, 'void');
const instruction = this._triggers[triggerName].matchTransition(oldValue, VOID_STATE);
return !!instruction;
});
if (hasRemoval) {
@ -115,8 +116,9 @@ export class DomAnimationEngine {
this._elementTriggerStates.set(element, lookupRef = {});
}
let oldValue = lookupRef.hasOwnProperty(property) ? lookupRef[property] : 'void';
let oldValue = lookupRef.hasOwnProperty(property) ? lookupRef[property] : VOID_STATE;
if (oldValue !== value) {
value = normalizeTriggerValue(value);
let instruction = trigger.matchTransition(oldValue, value);
if (!instruction) {
// we do this to make sure we always have an animation player so
@ -407,11 +409,11 @@ export class DomAnimationEngine {
Object.keys(stateDetails).forEach(triggerName => {
flushAgain = true;
const oldValue = stateDetails[triggerName];
const instruction = this._triggers[triggerName].matchTransition(oldValue, 'void');
const instruction = this._triggers[triggerName].matchTransition(oldValue, VOID_STATE);
if (instruction) {
players.push(this.animateTransition(element, instruction));
} else {
const event = makeAnimationEvent(element, triggerName, oldValue, 'void', '', 0);
const event = makeAnimationEvent(element, triggerName, oldValue, VOID_STATE, '', 0);
const player = new NoopAnimationPlayer();
this._queuePlayer(element, triggerName, player, event);
}
@ -515,3 +517,12 @@ function makeAnimationEvent(
totalTime: number): AnimationEvent {
return <AnimationEvent>{element, triggerName, fromState, toState, phaseName, totalTime};
}
function normalizeTriggerValue(value: any): string {
switch (typeof value) {
case 'boolean':
return value ? '1' : '0';
default:
return value ? value.toString() : null;
}
}

View File

@ -147,6 +147,46 @@ export function main() {
]);
});
it('should stringify boolean triggers to `1` and `0`', () => {
@Component({
selector: 'if-cmp',
template: `
<div [@myAnimation]="exp"></div>
`,
animations: [trigger(
'myAnimation',
[
transition('void => 1', [style({opacity: 0}), animate(1000, style({opacity: 1}))]),
transition('1 => 0', [style({opacity: 1}), animate(1000, style({opacity: 0}))])
])]
})
class Cmp {
exp: any = false;
}
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.get(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp = true;
fixture.detectChanges();
engine.flush();
expect(getLog().pop().keyframes).toEqual([
{offset: 0, opacity: '0'}, {offset: 1, opacity: '1'}
]);
cmp.exp = false;
fixture.detectChanges();
engine.flush();
expect(getLog().pop().keyframes).toEqual([
{offset: 0, opacity: '1'}, {offset: 1, opacity: '0'}
]);
});
it('should not throw an error if a trigger with the same name exists in separate components',
() => {
@Component({selector: 'cmp1', template: '...', animations: [trigger('trig', [])]})