Skip to content

Commit 0a82138

Browse files
fix(compiler): fixes regression with event parsing and animate prefix (angular#63470)
The new animations was not correctly looking for the `.` when parsing bindings. This resulted in arbitrary event bindings creating animate.leave instruction calls. fixes: angular#63466 PR Close angular#63470
1 parent 1a26fd3 commit 0a82138

File tree

7 files changed

+95
-2
lines changed

7 files changed

+95
-2
lines changed

packages/compiler-cli/test/compliance/test_cases/r3_view_compiler/animations/GOLDEN_PARTIAL.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,3 +471,39 @@ export declare class MyComponent {
471471
static ɵcmp: i0.ɵɵComponentDeclaration<MyComponent, "my-component", never, {}, {}, never, never, true, never>;
472472
}
473473

474+
/****************************************************************************************************
475+
* PARTIAL FILE: animate_prefix_with_event_listener.js
476+
****************************************************************************************************/
477+
import { Component } from '@angular/core';
478+
import * as i0 from "@angular/core";
479+
export class MyComponent {
480+
doSomething() { }
481+
}
482+
MyComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
483+
MyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyComponent, isStandalone: true, selector: "my-component", ngImport: i0, template: `
484+
<div>
485+
<p (animateABC)="doSomething()">Fading Content</p>
486+
</div>
487+
`, isInline: true });
488+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, decorators: [{
489+
type: Component,
490+
args: [{
491+
selector: 'my-component',
492+
template: `
493+
<div>
494+
<p (animateABC)="doSomething()">Fading Content</p>
495+
</div>
496+
`,
497+
}]
498+
}] });
499+
500+
/****************************************************************************************************
501+
* PARTIAL FILE: animate_prefix_with_event_listener.d.ts
502+
****************************************************************************************************/
503+
import * as i0 from "@angular/core";
504+
export declare class MyComponent {
505+
doSomething(): void;
506+
static ɵfac: i0.ɵɵFactoryDeclaration<MyComponent, never>;
507+
static ɵcmp: i0.ɵɵComponentDeclaration<MyComponent, "my-component", never, {}, {}, never, never, true, never>;
508+
}
509+

packages/compiler-cli/test/compliance/test_cases/r3_view_compiler/animations/TEST_CASES.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,23 @@
187187
"failureMessage": "Incorrect ɵɵanimateLeave() call"
188188
}
189189
]
190+
},
191+
{
192+
"description": "should not generate animate leave when using 'animate' as a binding prefix",
193+
"inputFiles": [
194+
"animate_prefix_with_event_listener.ts"
195+
],
196+
"expectations": [
197+
{
198+
"files": [
199+
{
200+
"expected": "animate_prefix_with_event_listener_template.js",
201+
"generated": "animate_prefix_with_event_listener.js"
202+
}
203+
],
204+
"failureMessage": "ɵɵanimateLeave() present when it should not be"
205+
}
206+
]
190207
}
191208
]
192209
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import {Component} from '@angular/core';
2+
3+
@Component({
4+
selector: 'my-component',
5+
template: `
6+
<div>
7+
<p (animateABC)="doSomething()">Fading Content</p>
8+
</div>
9+
`,
10+
})
11+
export class MyComponent {
12+
doSomething() {}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
MyComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], decls: 3, vars: 0, consts: [[3, "animateABC"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) {
2+
i0.ɵɵdomElementStart(0, "div")(1, "p", 0);
3+
i0.ɵɵdomListener("animateABC", function MyComponent_Template_p_animateABC_1_listener() { return ctx.doSomething(); });
4+
i0.ɵɵtext(2, "Fading Content");
5+
i0.ɵɵdomElementEnd()();
6+
} }, encapsulation: 2 });

packages/compiler/src/template_parser/binding_parser.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ export class BindingParser {
403403
targetMatchableAttrs,
404404
targetProps,
405405
);
406-
} else if (name.startsWith(ANIMATE_PREFIX)) {
406+
} else if (name.startsWith(`${ANIMATE_PREFIX}${PROPERTY_PARTS_SEPARATOR}`)) {
407407
this._parseAnimation(
408408
name,
409409
this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset),
@@ -780,7 +780,7 @@ export class BindingParser {
780780
if (isAssignmentEvent) {
781781
eventType = ParsedEventType.TwoWay;
782782
}
783-
if (name.startsWith(ANIMATE_PREFIX)) {
783+
if (name.startsWith(`${ANIMATE_PREFIX}${PROPERTY_PARTS_SEPARATOR}`)) {
784784
eventType = ParsedEventType.Animation;
785785
}
786786

packages/compiler/test/ml_parser/html_parser_spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,13 @@ describe('HtmlParser', () => {
435435
]);
436436
});
437437

438+
it('should not parse any other animate prefix binding as animate.leave', () => {
439+
expect(humanizeDom(parser.parse(`<div animateAbc="bar"></div>`, 'TestComp'))).toEqual([
440+
[html.Element, 'div', 0],
441+
[html.Attribute, 'animateAbc', 'bar', ['bar']],
442+
]);
443+
});
444+
438445
it('should parse both animate.enter and animate.leave as static attributes', () => {
439446
expect(
440447
humanizeDom(
@@ -487,6 +494,15 @@ describe('HtmlParser', () => {
487494
]);
488495
});
489496

497+
it('should not parse other animate prefixes as animate.leave', () => {
498+
expect(
499+
humanizeDom(parser.parse(`<div (animateXYZ)="onAnimation()"></div>`, 'TestComp')),
500+
).toEqual([
501+
[html.Element, 'div', 0],
502+
[html.Attribute, '(animateXYZ)', 'onAnimation()', ['onAnimation()']],
503+
]);
504+
});
505+
490506
it('should parse a combination of animate property and event bindings', () => {
491507
expect(
492508
humanizeDom(

packages/compiler/test/render3/r3_template_transform_spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,11 @@ describe('R3 template transform', () => {
424424
['Element', 'div'],
425425
['BoundEvent', 3, 'animate.leave', null, 'animateFn($event)'],
426426
]);
427+
428+
expectFromHtml(`<div (animateXYZ)="animateFn()"></div>`).toEqual([
429+
['Element', 'div'],
430+
['BoundEvent', 0, 'animateXYZ', null, 'animateFn()'],
431+
]);
427432
});
428433
});
429434

0 commit comments

Comments
 (0)