diff --git a/packages/animations/browser/src/render/dom_animation_engine.ts b/packages/animations/browser/src/render/dom_animation_engine.ts index c9c752a86b..9f7e9dfe90 100644 --- a/packages/animations/browser/src/render/dom_animation_engine.ts +++ b/packages/animations/browser/src/render/dom_animation_engine.ts @@ -106,8 +106,8 @@ export class DomAnimationEngine { this._elementTriggerStates.set(element, lookupRef = {}); } - let oldValue = lookupRef[property] || 'void'; - if (oldValue != value) { + let oldValue = lookupRef.hasOwnProperty(property) ? lookupRef[property] : 'void'; + if (oldValue !== value) { let instruction = trigger.matchTransition(oldValue, value); if (!instruction) { // we do this to make sure we always have an animation player so diff --git a/packages/core/test/animation/animation_integration_spec.ts b/packages/core/test/animation/animation_integration_spec.ts index 992385c70b..15c6559b29 100644 --- a/packages/core/test/animation/animation_integration_spec.ts +++ b/packages/core/test/animation/animation_integration_spec.ts @@ -65,6 +65,88 @@ export function main() { ]); }); + it('should only turn a view removal as into `void` state transition', () => { + @Component({ + selector: 'if-cmp', + template: ` +
+ `, + animations: [trigger( + 'myAnimation', + [ + transition( + 'void <=> *', [style({width: '0px'}), animate(1000, style({width: '100px'}))]), + transition( + '* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]), + ])] + }) + class Cmp { + exp1: any = false; + exp2: any = false; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp1 = true; + cmp.exp2 = null; + + fixture.detectChanges(); + engine.flush(); + + expect(getLog().pop().keyframes).toEqual([ + {offset: 0, width: '0px'}, {offset: 1, width: '100px'} + ]); + + cmp.exp2 = false; + + fixture.detectChanges(); + engine.flush(); + + expect(getLog().pop().keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); + + cmp.exp2 = 0; + + fixture.detectChanges(); + engine.flush(); + + expect(getLog().pop().keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); + + cmp.exp2 = ''; + + fixture.detectChanges(); + engine.flush(); + + expect(getLog().pop().keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); + + cmp.exp2 = undefined; + + fixture.detectChanges(); + engine.flush(); + + expect(getLog().pop().keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); + + cmp.exp1 = false; + cmp.exp2 = 'abc'; + + fixture.detectChanges(); + engine.flush(); + + expect(getLog().pop().keyframes).toEqual([ + {offset: 0, width: '0px'}, {offset: 1, width: '100px'} + ]); + }); + it('should not throw an error if a trigger with the same name exists in separate components', () => { @Component({selector: 'cmp1', template: '...', animations: [trigger('trig', [])]})