diff --git a/modules/@angular/compiler/src/animation/animation_parser.ts b/modules/@angular/compiler/src/animation/animation_parser.ts index bf5b7177e3..163c38aac3 100644 --- a/modules/@angular/compiler/src/animation/animation_parser.ts +++ b/modules/@angular/compiler/src/animation/animation_parser.ts @@ -132,9 +132,25 @@ function _parseAnimationStateTransition( return new AnimationStateTransitionAst(transitionExprs, stepsAst); } +function _parseAnimationAlias(alias: string, errors: AnimationParseError[]): string { + switch (alias) { + case ':enter': + return 'void => *'; + case ':leave': + return '* => void'; + default: + errors.push( + new AnimationParseError(`the transition alias value "${alias}" is not supported`)); + return '* => *'; + } +} + function _parseAnimationTransitionExpr( eventStr: string, errors: AnimationParseError[]): AnimationStateTransitionExpression[] { - var expressions: any[] /** TODO #9100 */ = []; + var expressions: AnimationStateTransitionExpression[] = []; + if (eventStr[0] == ':') { + eventStr = _parseAnimationAlias(eventStr, errors); + } var match = eventStr.match(/^(\*|[-\w]+)\s*()\s*(\*|[-\w]+)$/); if (!isPresent(match) || match.length < 4) { errors.push(new AnimationParseError(`the provided ${eventStr} is not of a supported format`)); diff --git a/modules/@angular/core/test/animation/animation_integration_spec.ts b/modules/@angular/core/test/animation/animation_integration_spec.ts index 622c0b3bc5..8b563edc4e 100644 --- a/modules/@angular/core/test/animation/animation_integration_spec.ts +++ b/modules/@angular/core/test/animation/animation_integration_spec.ts @@ -146,6 +146,87 @@ function declareTests({useJit}: {useJit: boolean}) { expect(kf[1]).toEqual([1, {'background': 'blue'}]); })); + describe('animation aliases', () => { + it('should animate the ":enter" animation alias as "void => *"', fakeAsync(() => { + TestBed.overrideComponent(DummyIfCmp, { + set: { + template: ` +
+ `, + animations: [trigger( + 'myAnimation', + [transition( + ':enter', + [style({'opacity': 0}), animate('500ms', style({opacity: 1}))])])] + } + }); + + const driver = TestBed.get(AnimationDriver) as MockAnimationDriver; + let fixture = TestBed.createComponent(DummyIfCmp); + var cmp = fixture.componentInstance; + cmp.exp = true; + fixture.detectChanges(); + + expect(driver.log.length).toEqual(1); + + var animation = driver.log[0]; + expect(animation['duration']).toEqual(500); + })); + + it('should animate the ":leave" animation alias as "* => void"', fakeAsync(() => { + TestBed.overrideComponent(DummyIfCmp, { + set: { + template: ` +
+ `, + animations: [trigger( + 'myAnimation', + [transition(':leave', [animate('999ms', style({opacity: 0}))])])] + } + }); + + const driver = TestBed.get(AnimationDriver) as MockAnimationDriver; + let fixture = TestBed.createComponent(DummyIfCmp); + var cmp = fixture.componentInstance; + cmp.exp = true; + fixture.detectChanges(); + + expect(driver.log.length).toEqual(0); + + cmp.exp = false; + fixture.detectChanges(); + + expect(driver.log.length).toEqual(1); + + var animation = driver.log[0]; + expect(animation['duration']).toEqual(999); + })); + + it('should throw an error when an unsupported alias is detected which is prefixed a colon value', + fakeAsync(() => { + TestBed.overrideComponent(DummyIfCmp, { + set: { + template: ` +
+ `, + animations: [trigger( + 'myAnimation', + [transition(':dont_leave_me', [animate('444ms', style({opacity: 0}))])])] + } + }); + + var message = ''; + try { + let fixture = TestBed.createComponent(DummyIfCmp); + } catch (e) { + message = e.message; + } + + expect(message).toMatch( + /the transition alias value ":dont_leave_me" is not supported/); + })); + }); + it('should animate between * and void and back even when no expression is assigned', fakeAsync(() => { TestBed.overrideComponent(DummyIfCmp, {