fix(ivy): set ng-reflect properties for unbound directive inputs (#29973)

We only set ng-reflect properties on directive input bindings.
This PR ensures that we also add ng-reflect properties on unbound inputs for backwards compatibility.

FW-1266 #resolve

PR Close #29973
This commit is contained in:
Olivier Combe
2019-04-18 14:22:32 +02:00
committed by Ben Lesh
parent d9ce8a4ab5
commit 4e13700ad2
4 changed files with 94 additions and 35 deletions

View File

@ -1687,17 +1687,27 @@ function declareTests(config?: {useJit: boolean}) {
describe('logging property updates', () => {
it('should reflect property values as attributes', () => {
TestBed.configureTestingModule({declarations: [MyComp, MyDir]});
const template = '<div>' +
'<div my-dir [elprop]="ctxProp"></div>' +
'</div>';
TestBed.overrideComponent(MyComp, {set: {template}});
TestBed.overrideComponent(
MyComp, {set: {template: `<div my-dir [elprop]="ctxProp"></div>`}});
const fixture = TestBed.createComponent(MyComp);
fixture.componentInstance.ctxProp = 'hello';
fixture.detectChanges();
expect(getDOM().getInnerHTML(fixture.nativeElement))
.toContain('ng-reflect-dir-prop="hello"');
const html = getDOM().getInnerHTML(fixture.nativeElement);
expect(html).toContain('ng-reflect-dir-prop="hello"');
});
it('should reflect property values on unbound inputs', () => {
TestBed.configureTestingModule({declarations: [MyComp, MyDir]});
TestBed.overrideComponent(
MyComp, {set: {template: `<div my-dir elprop="hello" title="Reflect test"></div>`}});
const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges();
const html = getDOM().getInnerHTML(fixture.nativeElement);
expect(html).toContain('ng-reflect-dir-prop="hello"');
expect(html).not.toContain('ng-reflect-title');
});
it(`should work with prop names containing '$'`, () => {
@ -1705,23 +1715,54 @@ function declareTests(config?: {useJit: boolean}) {
const fixture = TestBed.createComponent(ParentCmp);
fixture.detectChanges();
expect(getDOM().getInnerHTML(fixture.nativeElement)).toContain('ng-reflect-test_="hello"');
const html = getDOM().getInnerHTML(fixture.nativeElement);
expect(html).toContain('ng-reflect-test_="hello"');
});
it('should reflect property values on template comments', () => {
const fixture =
TestBed.configureTestingModule({declarations: [MyComp]})
.overrideComponent(
MyComp, {set: {template: '<ng-template [ngIf]="ctxBoolProp"></ng-template>'}})
MyComp, {set: {template: `<ng-template [ngIf]="ctxBoolProp"></ng-template>`}})
.createComponent(MyComp);
fixture.componentInstance.ctxBoolProp = true;
fixture.detectChanges();
expect(getDOM().getInnerHTML(fixture.nativeElement))
.toContain('"ng\-reflect\-ng\-if"\: "true"');
const html = getDOM().getInnerHTML(fixture.nativeElement);
expect(html).toContain('"ng-reflect-ng-if": "true"');
});
it('should reflect property values on ng-containers', () => {
const fixture =
TestBed.configureTestingModule({declarations: [MyComp]})
.overrideComponent(
MyComp,
{set: {template: `<ng-container *ngIf="ctxBoolProp">content</ng-container>`}})
.createComponent(MyComp);
fixture.componentInstance.ctxBoolProp = true;
fixture.detectChanges();
const html = getDOM().getInnerHTML(fixture.nativeElement);
expect(html).toContain('"ng-reflect-ng-if": "true"');
});
it('should reflect property values of multiple directive bound to the same input name',
() => {
TestBed.configureTestingModule({declarations: [MyComp, MyDir, MyDir2]});
TestBed.overrideComponent(
MyComp, {set: {template: `<div my-dir my-dir2 [elprop]="ctxProp"></div>`}});
const fixture = TestBed.createComponent(MyComp);
fixture.componentInstance.ctxProp = 'hello';
fixture.detectChanges();
const html = getDOM().getInnerHTML(fixture.nativeElement);
expect(html).toContain('ng-reflect-dir-prop="hello"');
expect(html).toContain('ng-reflect-dir-prop2="hello"');
});
it('should indicate when toString() throws', () => {
TestBed.configureTestingModule({declarations: [MyComp, MyDir]});
const template = '<div my-dir [elprop]="toStringThrow"></div>';
@ -2019,6 +2060,12 @@ class MyDir {
constructor() { this.dirProp = ''; }
}
@Directive({selector: '[my-dir2]', inputs: ['dirProp2: elprop'], exportAs: 'mydir2'})
class MyDir2 {
dirProp2: string;
constructor() { this.dirProp2 = ''; }
}
@Directive({selector: '[title]', inputs: ['title']})
class DirectiveWithTitle {
// TODO(issue/24571): remove '!'.