Skip to content

Commit 488d962

Browse files
JeanMechethePunderWoman
authored andcommitted
fix(compiler): Don't bind inputs/outputs for data- attributes
This is to improve consistency and match developer expectations. This syntax was already deprecated a long time ago. If you want to bind a data attribute, use the `attr.` prefix (which was already supported). BREAKING CHANGE: data prefixed attribute no-longer bind inputs nor outputs. fixes #26406
1 parent 5ac1c02 commit 488d962

File tree

3 files changed

+13
-50
lines changed

3 files changed

+13
-50
lines changed

packages/compiler/src/render3/r3_template_transform.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,6 @@ class HtmlAstToIvyAst implements html.Visitor {
619619

620620
for (const attribute of attrs) {
621621
let hasBinding = false;
622-
const normalizedName = normalizeAttributeName(attribute.name);
623622

624623
// `*attr` defines template bindings
625624
let isTemplateBinding = false;
@@ -628,7 +627,7 @@ class HtmlAstToIvyAst implements html.Visitor {
628627
i18nAttrsMeta[attribute.name] = attribute.i18n;
629628
}
630629

631-
if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX)) {
630+
if (attribute.name.startsWith(TEMPLATE_ATTR_PREFIX)) {
632631
// *-attributes
633632
if (elementHasInlineTemplate) {
634633
this.reportError(
@@ -639,7 +638,7 @@ class HtmlAstToIvyAst implements html.Visitor {
639638
isTemplateBinding = true;
640639
elementHasInlineTemplate = true;
641640
const templateValue = attribute.value;
642-
const templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX.length);
641+
const templateKey = attribute.name.substring(TEMPLATE_ATTR_PREFIX.length);
643642

644643
const parsedVariables: ParsedVariable[] = [];
645644
const absoluteValueOffset = attribute.valueSpan
@@ -705,7 +704,7 @@ class HtmlAstToIvyAst implements html.Visitor {
705704
variables: t.Variable[],
706705
references: t.Reference[],
707706
) {
708-
const name = normalizeAttributeName(attribute.name);
707+
const name = attribute.name;
709708
const value = attribute.value;
710709
const srcSpan = attribute.sourceSpan;
711710
const absoluteOffset = attribute.valueSpan
@@ -715,8 +714,7 @@ class HtmlAstToIvyAst implements html.Visitor {
715714
function createKeySpan(srcSpan: ParseSourceSpan, prefix: string, identifier: string) {
716715
// We need to adjust the start location for the keySpan to account for the removed 'data-'
717716
// prefix from `normalizeAttributeName`.
718-
const normalizationAdjustment = attribute.name.length - name.length;
719-
const keySpanStart = srcSpan.start.moveBy(prefix.length + normalizationAdjustment);
717+
const keySpanStart = srcSpan.start.moveBy(prefix.length);
720718
const keySpanEnd = keySpanStart.moveBy(identifier.length);
721719
return new ParseSourceSpan(keySpanStart, keySpanEnd, keySpanStart, identifier);
722720
}
@@ -1254,10 +1252,6 @@ class NonBindableVisitor implements html.Visitor {
12541252

12551253
const NON_BINDABLE_VISITOR = new NonBindableVisitor();
12561254

1257-
function normalizeAttributeName(attrName: string): string {
1258-
return /^data-/i.test(attrName) ? attrName.substring(5) : attrName;
1259-
}
1260-
12611255
function addEvents(events: ParsedEvent[], boundEvents: t.BoundEvent[]) {
12621256
boundEvents.push(...events.map((e) => t.BoundEvent.fromParsedEvent(e)));
12631257
}

packages/compiler/test/render3/r3_ast_spans_spec.ts

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ describe('R3 AST source spans', () => {
398398
it('is correct for bound properties via data-', () => {
399399
expectFromHtml('<div data-prop="{{v}}"></div>').toEqual([
400400
['Element', '<div data-prop="{{v}}"></div>', '<div data-prop="{{v}}">', '</div>'],
401-
['BoundAttribute', 'data-prop="{{v}}"', 'prop', '{{v}}'],
401+
['BoundAttribute', 'data-prop="{{v}}"', 'data-prop', '{{v}}'],
402402
]);
403403
});
404404

@@ -506,15 +506,15 @@ describe('R3 AST source spans', () => {
506506
]);
507507
});
508508

509-
it('is correct for reference via data-ref-...', () => {
509+
it('is correct for data-ref-... attribute', () => {
510510
expectFromHtml('<ng-template data-ref-a></ng-template>').toEqual([
511511
[
512512
'Template',
513513
'<ng-template data-ref-a></ng-template>',
514514
'<ng-template data-ref-a>',
515515
'</ng-template>',
516516
],
517-
['Reference', 'data-ref-a', 'a', '<empty>'],
517+
['TextAttribute', 'data-ref-a', 'data-ref-a', '<empty>'],
518518
]);
519519
});
520520

@@ -530,15 +530,15 @@ describe('R3 AST source spans', () => {
530530
]);
531531
});
532532

533-
it('is correct for variables via data-let-...', () => {
533+
it('is correct for data-let-... attribute', () => {
534534
expectFromHtml('<ng-template data-let-a="b"></ng-template>').toEqual([
535535
[
536536
'Template',
537537
'<ng-template data-let-a="b"></ng-template>',
538538
'<ng-template data-let-a="b">',
539539
'</ng-template>',
540540
],
541-
['Variable', 'data-let-a="b"', 'a', 'b'],
541+
['TextAttribute', 'data-let-a="b"', 'data-let-a', 'b'],
542542
]);
543543
});
544544

@@ -664,10 +664,10 @@ describe('R3 AST source spans', () => {
664664
]);
665665
});
666666

667-
it('is correct for bound events via data-on-', () => {
667+
it('is correct for text attribute via data-on-', () => {
668668
expectFromHtml('<div data-on-event="v"></div>').toEqual([
669669
['Element', '<div data-on-event="v"></div>', '<div data-on-event="v">', '</div>'],
670-
['BoundEvent', 'data-on-event="v"', 'event', 'v'],
670+
['TextAttribute', 'data-on-event="v"', 'data-on-event', 'v'],
671671
]);
672672
});
673673

@@ -687,11 +687,10 @@ describe('R3 AST source spans', () => {
687687
]);
688688
});
689689

690-
it('is correct for bound events and properties via data-bindon-', () => {
690+
it('is correct for TextAttribute and properties via data-bindon-', () => {
691691
expectFromHtml('<div data-bindon-prop="v"></div>').toEqual([
692692
['Element', '<div data-bindon-prop="v"></div>', '<div data-bindon-prop="v">', '</div>'],
693-
['BoundAttribute', 'data-bindon-prop="v"', 'prop', 'v'],
694-
['BoundEvent', 'data-bindon-prop="v"', 'prop', 'v'],
693+
['TextAttribute', 'data-bindon-prop="v"', 'data-bindon-prop', 'v'],
695694
]);
696695
});
697696

@@ -724,13 +723,6 @@ describe('R3 AST source spans', () => {
724723
['Reference', 'ref-a', 'a', '<empty>'],
725724
]);
726725
});
727-
728-
it('is correct for references via data-ref-', () => {
729-
expectFromHtml('<div ref-a></div>').toEqual([
730-
['Element', '<div ref-a></div>', '<div ref-a>', '</div>'],
731-
['Reference', 'ref-a', 'a', '<empty>'],
732-
]);
733-
});
734726
});
735727

736728
describe('ICU expressions', () => {

packages/language-service/test/grp3/quick_info_spec.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -225,14 +225,6 @@ describe('quick info', () => {
225225
});
226226
});
227227

228-
it('should work for data-let- syntax', () => {
229-
expectQuickInfo({
230-
templateOverride: `<ng-template ngFor data-let-he¦ro [ngForOf]="heroes">{{hero}}</ng-template>`,
231-
expectedSpanText: 'hero',
232-
expectedDisplayString: '(variable) hero: Hero',
233-
});
234-
});
235-
236228
it('should get tags', () => {
237229
const templateOverride = '<div depr¦ecated></div>';
238230
const text = templateOverride.replace('¦', '');
@@ -264,11 +256,6 @@ describe('quick info', () => {
264256
expectedSpanText: 'tcName',
265257
expectedDisplayString: '(property) TestComponent.name: string',
266258
});
267-
expectQuickInfo({
268-
templateOverride: `<test-comp data-bind-tcN¦ame="name"></test-comp>`,
269-
expectedSpanText: 'tcName',
270-
expectedDisplayString: '(property) TestComponent.name: string',
271-
});
272259
});
273260

274261
it('should work for structural directive inputs ngForTrackBy', () => {
@@ -322,11 +309,6 @@ describe('quick info', () => {
322309
expectedSpanText: 'test',
323310
expectedDisplayString: '(event) TestComponent.testEvent: EventEmitter<string>',
324311
});
325-
expectQuickInfo({
326-
templateOverride: `<test-comp data-on-te¦st="myClick($event)"></test-comp>`,
327-
expectedSpanText: 'test',
328-
expectedDisplayString: '(event) TestComponent.testEvent: EventEmitter<string>',
329-
});
330312
});
331313

332314
it('should work for $event from EventEmitter', () => {
@@ -375,11 +357,6 @@ describe('quick info', () => {
375357
expectedSpanText: 'chart',
376358
expectedDisplayString: '(reference) chart: HTMLDivElement',
377359
});
378-
expectQuickInfo({
379-
templateOverride: `<div data-ref-ch¦art></div>`,
380-
expectedSpanText: 'chart',
381-
expectedDisplayString: '(reference) chart: HTMLDivElement',
382-
});
383360
});
384361

385362
it('should work for click output from native element', () => {

0 commit comments

Comments
 (0)