diff --git a/modules/@angular/compiler-cli/integrationtest/src/animate.ts b/modules/@angular/compiler-cli/integrationtest/src/animate.ts index 50f8e83b6c..e7f1955b4d 100644 --- a/modules/@angular/compiler-cli/integrationtest/src/animate.ts +++ b/modules/@angular/compiler-cli/integrationtest/src/animate.ts @@ -23,7 +23,7 @@ import {AUTO_STYLE, Component, animate, state, style, transition, trigger} from
-
+
Look at this box
` diff --git a/modules/@angular/compiler/src/template_parser.ts b/modules/@angular/compiler/src/template_parser.ts index 71956556be..2f3994e645 100644 --- a/modules/@angular/compiler/src/template_parser.ts +++ b/modules/@angular/compiler/src/template_parser.ts @@ -466,8 +466,9 @@ class TemplateParseVisitor implements HtmlAstVisitor { if (isPresent(bindParts)) { hasBinding = true; if (isPresent(bindParts[1])) { // match: bind-prop - this._parseProperty( - bindParts[8], attrValue, attr.sourceSpan, targetMatchableAttrs, targetProps); + this._parsePropertyOrAnimation( + bindParts[8], attrValue, attr.sourceSpan, targetMatchableAttrs, targetProps, + targetAnimationProps); } else if (isPresent(bindParts[2])) { // match: var-name / var-name="iden" var identifier = bindParts[8]; @@ -500,23 +501,31 @@ class TemplateParseVisitor implements HtmlAstVisitor { bindParts[8], attrValue, attr.sourceSpan, targetMatchableAttrs, targetEvents); } else if (isPresent(bindParts[6])) { // match: bindon-prop - this._parseProperty( - bindParts[8], attrValue, attr.sourceSpan, targetMatchableAttrs, targetProps); + this._parsePropertyOrAnimation( + bindParts[8], attrValue, attr.sourceSpan, targetMatchableAttrs, targetProps, + targetAnimationProps); this._parseAssignmentEvent( bindParts[8], attrValue, attr.sourceSpan, targetMatchableAttrs, targetEvents); } else if (isPresent(bindParts[7])) { // match: animate-name + if (attrName[0] == '@' && isPresent(attrValue) && attrValue.length > 0) { + this._reportError( + `Assigning animation triggers via @prop="exp" attributes with an expression is deprecated. Use [@prop]="exp" instead!`, + attr.sourceSpan, ParseErrorLevel.WARNING); + } this._parseAnimation( bindParts[8], attrValue, attr.sourceSpan, targetMatchableAttrs, targetAnimationProps); } else if (isPresent(bindParts[9])) { // match: [(expr)] - this._parseProperty( - bindParts[9], attrValue, attr.sourceSpan, targetMatchableAttrs, targetProps); + this._parsePropertyOrAnimation( + bindParts[9], attrValue, attr.sourceSpan, targetMatchableAttrs, targetProps, + targetAnimationProps); this._parseAssignmentEvent( bindParts[9], attrValue, attr.sourceSpan, targetMatchableAttrs, targetEvents); } else if (isPresent(bindParts[10])) { // match: [expr] - this._parseProperty( - bindParts[10], attrValue, attr.sourceSpan, targetMatchableAttrs, targetProps); + this._parsePropertyOrAnimation( + bindParts[10], attrValue, attr.sourceSpan, targetMatchableAttrs, targetProps, + targetAnimationProps); } else if (isPresent(bindParts[11])) { // match: (event) this._parseEvent( @@ -555,12 +564,18 @@ class TemplateParseVisitor implements HtmlAstVisitor { targetRefs.push(new ElementOrDirectiveRef(identifier, value, sourceSpan)); } - private _parseProperty( + private _parsePropertyOrAnimation( name: string, expression: string, sourceSpan: ParseSourceSpan, - targetMatchableAttrs: string[][], targetProps: BoundElementOrDirectiveProperty[]) { - this._parsePropertyAst( - name, this._parseBinding(expression, sourceSpan), sourceSpan, targetMatchableAttrs, - targetProps); + targetMatchableAttrs: string[][], targetProps: BoundElementOrDirectiveProperty[], + targetAnimationProps: BoundElementPropertyAst[]) { + if (name[0] == '@') { + this._parseAnimation( + name.substr(1), expression, sourceSpan, targetMatchableAttrs, targetAnimationProps); + } else { + this._parsePropertyAst( + name, this._parseBinding(expression, sourceSpan), sourceSpan, targetMatchableAttrs, + targetProps); + } } private _parseAnimation( diff --git a/modules/@angular/compiler/test/template_parser_spec.ts b/modules/@angular/compiler/test/template_parser_spec.ts index cc585adb9c..e1db43c89a 100644 --- a/modules/@angular/compiler/test/template_parser_spec.ts +++ b/modules/@angular/compiler/test/template_parser_spec.ts @@ -282,6 +282,34 @@ export function main() { [BoundElementPropertyAst, PropertyBindingType.Animation, 'something', 'value2', null] ]); }); + + it('should parse bound properties via @ and not report them as attributes and also report a deprecation warning', + () => { + expect(humanizeTplAst(parse('
', []))).toEqual([ + [ElementAst, 'div'], + [ + BoundElementPropertyAst, PropertyBindingType.Animation, 'something', 'value2', null + ] + ]); + + expect(console.warnings).toEqual([[ + 'Template parse warnings:', + `Assigning animation triggers via @prop="exp" attributes with an expression is deprecated. Use [@prop]="exp" instead! ("
]@something="value2">"): TestComp@0:5` + ].join('\n')]); + }); + + it('should not issue a warning when an animation property is bound without an expression', + () => { + humanizeTplAst(parse('
', [])); + expect(console.warnings.length).toEqual(0); + }); + + it('should parse bound properties via [@] and not report them as attributes', () => { + expect(humanizeTplAst(parse('
', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Animation, 'something', 'value2', null] + ]); + }); }); describe('events', () => { diff --git a/modules/@angular/core/src/animation/metadata.ts b/modules/@angular/core/src/animation/metadata.ts index f7d85a89a5..5be9b569f1 100644 --- a/modules/@angular/core/src/animation/metadata.ts +++ b/modules/@angular/core/src/animation/metadata.ts @@ -520,7 +520,7 @@ export function keyframes(steps: AnimationStyleMetadata[]): AnimationKeyframesSe * * ```html * - *
...
+ *
...
* ``` * * #### The final `animate` call @@ -569,7 +569,7 @@ export function transition(stateChangeExpr: string, steps: AnimationMetadata | A * {@link ComponentMetadata#animations-anchor animations section}. An animation trigger can * be placed on an element within a template by referencing the name of the * trigger followed by the expression value that the trigger is bound to - * (in the form of `@triggerName="expression"`. + * (in the form of `[@triggerName]="expression"`. * * ### Usage * @@ -601,7 +601,7 @@ export function transition(stateChangeExpr: string, steps: AnimationMetadata | A * * ```html * - *
...
+ *
...
* ``` * * ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview)) diff --git a/modules/@angular/core/test/animation/animation_integration_spec.ts b/modules/@angular/core/test/animation/animation_integration_spec.ts index 2ffc43df30..e165fb8f8e 100644 --- a/modules/@angular/core/test/animation/animation_integration_spec.ts +++ b/modules/@angular/core/test/animation/animation_integration_spec.ts @@ -56,7 +56,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { makeAnimationCmp( - tcb, '
', + tcb, '
', trigger( 'myAnimation', [transition( @@ -82,7 +82,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { makeAnimationCmp( - tcb, '
', + tcb, '
', trigger( 'myAnimation', [transition( @@ -152,7 +152,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { tcb = tcb.overrideTemplate(DummyIfCmp, ` -
+
`); tcb.overrideAnimations(DummyIfCmp, [trigger( 'myAnimation', @@ -565,8 +565,8 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { tcb = tcb.overrideTemplate(DummyIfCmp, ` -
-
+
+
`); tcb.overrideAnimations( DummyIfCmp, @@ -629,7 +629,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { makeAnimationCmp( - tcb, '
', + tcb, '
', trigger( 'myAnimation', [transition('* => void', [animate(1000, style({'opacity': 0}))])]), @@ -661,7 +661,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { makeAnimationCmp( - tcb, '
', + tcb, '
', trigger('myAnimation', [transition( '* => *', [ @@ -693,7 +693,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { makeAnimationCmp( - tcb, '
', + tcb, '
', [ trigger( 'one', @@ -754,7 +754,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { makeAnimationCmp( - tcb, '
', + tcb, '
', [trigger( 'status', [ @@ -784,7 +784,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { makeAnimationCmp( - tcb, '
', + tcb, '
', [trigger( 'status', [ @@ -841,7 +841,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { makeAnimationCmp( - tcb, '
', + tcb, '
', [trigger( 'status', [ @@ -868,7 +868,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { makeAnimationCmp( - tcb, '
', + tcb, '
', [trigger( 'status', [ @@ -897,7 +897,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { makeAnimationCmp( - tcb, '
', + tcb, '
', [trigger( 'status', [ @@ -958,7 +958,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { makeAnimationCmp( - tcb, '
', + tcb, '
', [trigger( 'status', [ @@ -1003,7 +1003,7 @@ function declareTests({useJit}: {useJit: boolean}) { [TestComponentBuilder, AnimationDriver], fakeAsync((tcb: TestComponentBuilder, driver: MockAnimationDriver) => { makeAnimationCmp( - tcb, '
', + tcb, '
', [trigger( 'status', [ @@ -1042,7 +1042,7 @@ function declareTests({useJit}: {useJit: boolean}) { selector: 'if-cmp', directives: [NgIf], template: ` -
+
` }) class DummyIfCmp { diff --git a/modules/@angular/examples/core/animation/ts/dsl/animation_example.ts b/modules/@angular/examples/core/animation/ts/dsl/animation_example.ts index 1d5bf934d0..752ee1309a 100644 --- a/modules/@angular/examples/core/animation/ts/dsl/animation_example.ts +++ b/modules/@angular/examples/core/animation/ts/dsl/animation_example.ts @@ -35,7 +35,7 @@ import {Component, animate, state, style, transition, trigger} from '@angular/co
-
+
Look at this box
` diff --git a/modules/playground/src/animate/app/animate-app.ts b/modules/playground/src/animate/app/animate-app.ts index 9256a5c101..d77581a522 100644 --- a/modules/playground/src/animate/app/animate-app.ts +++ b/modules/playground/src/animate/app/animate-app.ts @@ -22,7 +22,7 @@ import { selector: 'animate-app', styleUrls: ['css/animate-app.css'], template: ` -
+
| @@ -30,7 +30,7 @@ import {
-
+
{{ item }}