fix(compiler): support directive inputs with interpolations on <ng-template>s (#35984)

Prior to this commit, Ivy compiler didn't handle directive inputs with interpolations located on `<ng-template>` elements (e.g. `<ng-template dir="{{ field }}">`). That was the case for regular inputs as well as inputs that should be processed via i18n subsystem (e.g. `<ng-template i18n-dir dir="Hello {{ name }}">`). This commit adds support for such expressions for explicit `<ng-template>`s as well as a number of tests to confirm the behavior.

Fixes #35752.

PR Close #35984
This commit is contained in:
Andrew Kushnir
2020-03-09 21:49:02 -07:00
parent 3fa895298d
commit 79659ee5aa
5 changed files with 323 additions and 12 deletions

View File

@ -548,6 +548,95 @@ describe('compiler compliance: template', () => {
});
it('should allow directive inputs as an interpolated prop on <ng-template>', () => {
const files = {
app: {
'spec.ts': `
import {Component, Directive, Input} from '@angular/core';
@Directive({selector: '[dir]'})
class WithInput {
@Input() dir: string = '';
}
@Component({
selector: 'my-app',
template: '<ng-template dir="{{ message }}"></ng-template>',
})
export class TestComp {
message = 'Hello';
}
`
}
};
const result = compile(files, angularFiles);
const expectedTemplate = `
consts: [[${AttributeMarker.Bindings}, "dir"]],
template: function TestComp_Template(rf, ctx) {
if (rf & 1) {
$i0$.ɵɵtemplate(0, $TestComp_ng_template_0_Template$, 0, 0, "ng-template", 0);
}
if (rf & 2) {
$i0$.ɵɵpropertyInterpolate("dir", ctx.message);
}
},
`;
expectEmit(result.source, expectedTemplate, 'Incorrect template');
});
it('should allow directive inputs as an interpolated prop on <ng-template> (with structural directives)',
() => {
const files = {
app: {
'spec.ts': `
import {Component, Directive, Input} from '@angular/core';
@Directive({selector: '[dir]'})
class WithInput {
@Input() dir: string = '';
}
@Component({
selector: 'my-app',
template: '<ng-template *ngIf="true" dir="{{ message }}"></ng-template>',
})
export class TestComp {
message = 'Hello';
}
`
}
};
const result = compile(files, angularFiles);
// Expect that `ɵɵpropertyInterpolate` is generated in the inner template function.
const expectedInnerTemplate = `
function $TestComp_0_Template$(rf, ctx) {
if (rf & 1) {
$i0$.ɵɵtemplate(0, $TestComp_0_ng_template_0_Template$, 0, 0, "ng-template", 1);
}
if (rf & 2) {
const $ctx_r0$ = i0.ɵɵnextContext();
$i0$.ɵɵpropertyInterpolate("dir", $ctx_r0$.message);
}
}
`;
expectEmit(result.source, expectedInnerTemplate, 'Incorrect template');
// Main template should just contain *ngIf property.
const expectedMainTemplate = `
consts: [[4, "ngIf"], [3, "dir"]],
template: function TestComp_Template(rf, ctx) {
if (rf & 1) {
$i0$.ɵɵtemplate(0, $TestComp_0_Template$, 1, 1, undefined, 0);
}
if (rf & 2) {
$i0$.ɵɵproperty("ngIf", true);
}
},
`;
expectEmit(result.source, expectedMainTemplate, 'Incorrect template');
});
it('should create unique template function names even for similar nested template structures',
() => {
const files = {