fix(core): do not use unbound attributes as inputs to structural directives (#36441)

Prior to this commit unbound attributes were treated as possible inputs to structural directives. Since structural directives can only accepts inputs defined using microsyntax expression (e.g. `<div *dir="exp">`), such unbound attributes should not be considered as inputs. This commit aligns Ivy and View Engine behavior and avoids using unbound attributes as inputs to structural directives.

PR Close #36441
This commit is contained in:
Andrew Kushnir
2020-04-05 18:35:37 -07:00
committed by Matias Niemelä
parent 0bd50e2e50
commit c0ed57db76
5 changed files with 112 additions and 6 deletions

View File

@ -420,6 +420,93 @@ describe('directives', () => {
expect(dirInstance!.dir).toBe('Hello');
});
it('should not set structural directive inputs from static element attrs', () => {
const dirInstances: StructuralDir[] = [];
@Directive({selector: '[dir]'})
class StructuralDir {
constructor() {
dirInstances.push(this);
}
@Input() dirOf!: number[];
@Input() dirUnboundInput: any;
}
@Component({
template: `
<!-- Regular form of structural directive -->
<div *dir="let item of items" dirUnboundInput>Some content</div>
<!-- De-sugared version of the same structural directive -->
<ng-template dir let-item [dirOf]="items" dirUnboundInput>
<div>Some content</div>
</ng-template>
`,
})
class App {
items: number[] = [1, 2, 3];
}
TestBed.configureTestingModule({
declarations: [App, StructuralDir],
});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const [regularDir, desugaredDir] = dirInstances;
// When directive is used as a structural one, the `dirUnboundInput` should not be treated as
// an input.
expect(regularDir.dirUnboundInput).toBe(undefined);
// In de-sugared version the `dirUnboundInput` acts as a regular input, so it should be set
// to an empty string.
expect(desugaredDir.dirUnboundInput).toBe('');
});
it('should not set structural directive inputs from element bindings', () => {
const dirInstances: StructuralDir[] = [];
@Directive({selector: '[dir]'})
class StructuralDir {
constructor() {
dirInstances.push(this);
}
@Input() dirOf!: number[];
@Input() title: any;
}
@Component({
template: `
<!-- Regular form of structural directive -->
<div *dir="let item of items" [title]="title">Some content</div>
<!-- De-sugared version of the same structural directive -->
<ng-template dir let-item [dirOf]="items" [title]="title">
<div>Some content</div>
</ng-template>
`,
})
class App {
items: number[] = [1, 2, 3];
title: string = 'element title';
}
TestBed.configureTestingModule({
declarations: [App, StructuralDir],
});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const [regularDir, desugaredDir] = dirInstances;
// When directive is used as a structural one, the `title` should not be treated as an input.
expect(regularDir.title).toBe(undefined);
// In de-sugared version the `title` acts as a regular input, so it should be set.
expect(desugaredDir.title).toBe('element title');
});
});
describe('outputs', () => {

View File

@ -461,6 +461,9 @@
{
"name": "isFactory"
},
{
"name": "isInlineTemplate"
},
{
"name": "isLContainer"
},

View File

@ -860,6 +860,9 @@
{
"name": "isInHostBindings"
},
{
"name": "isInlineTemplate"
},
{
"name": "isJsObject"
},