fix(compiler): update compiler to flatten nested template fns (#24943)
PR Close #24943
This commit is contained in:
parent
87419097da
commit
fe14f180a6
|
@ -541,6 +541,17 @@ describe('compiler compliance', () => {
|
||||||
const MyComponentDefinition = `
|
const MyComponentDefinition = `
|
||||||
const $c1$ = ["foo", ""];
|
const $c1$ = ["foo", ""];
|
||||||
const $c2$ = ["if", ""];
|
const $c2$ = ["if", ""];
|
||||||
|
function MyComponent_li_Template_2(rf, ctx0, ctx) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵE(0, "li");
|
||||||
|
$r3$.ɵT(1);
|
||||||
|
$r3$.ɵe();
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
const $foo$ = $r3$.ɵr(1, 1);
|
||||||
|
$r3$.ɵt(1, $r3$.ɵi2("", ctx.salutation, " ", $foo$, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
…
|
…
|
||||||
MyComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
MyComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
||||||
type: MyComponent,
|
type: MyComponent,
|
||||||
|
@ -552,17 +563,6 @@ describe('compiler compliance', () => {
|
||||||
$r3$.ɵC(2, MyComponent_li_Template_2, null, $c2$);
|
$r3$.ɵC(2, MyComponent_li_Template_2, null, $c2$);
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
}
|
}
|
||||||
const $foo$ = $r3$.ɵld(1);
|
|
||||||
function MyComponent_li_Template_2(rf, ctx0) {
|
|
||||||
if (rf & 1) {
|
|
||||||
$r3$.ɵE(0, "li");
|
|
||||||
$r3$.ɵT(1);
|
|
||||||
$r3$.ɵe();
|
|
||||||
}
|
|
||||||
if (rf & 2) {
|
|
||||||
$r3$.ɵt(1, $r3$.ɵi2("", ctx.salutation, " ", $foo$, ""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
directives:[IfDirective]
|
directives:[IfDirective]
|
||||||
});`;
|
});`;
|
||||||
|
@ -1173,8 +1173,8 @@ describe('compiler compliance', () => {
|
||||||
$r3$.ɵEe(0, "input", null, $c1$);
|
$r3$.ɵEe(0, "input", null, $c1$);
|
||||||
$r3$.ɵT(2);
|
$r3$.ɵT(2);
|
||||||
}
|
}
|
||||||
const $user$ = $r3$.ɵld(1);
|
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
|
const $user$ = $r3$.ɵld(1);
|
||||||
$r3$.ɵt(2, $r3$.ɵi1("Hello ", $user$.value, "!"));
|
$r3$.ɵt(2, $r3$.ɵi1("Hello ", $user$.value, "!"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1187,6 +1187,97 @@ describe('compiler compliance', () => {
|
||||||
expectEmit(source, MyComponentDefinition, 'Incorrect MyComponent.ngComponentDef');
|
expectEmit(source, MyComponentDefinition, 'Incorrect MyComponent.ngComponentDef');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('local references in nested views', () => {
|
||||||
|
const files = {
|
||||||
|
app: {
|
||||||
|
'spec.ts': `
|
||||||
|
import {Component, Directive, NgModule, TemplateRef} from '@angular/core';
|
||||||
|
|
||||||
|
@Directive({selector: '[if]'})
|
||||||
|
export class IfDirective {
|
||||||
|
constructor(template: TemplateRef<any>) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-component',
|
||||||
|
template: \`
|
||||||
|
<div #foo></div>
|
||||||
|
{{foo}}
|
||||||
|
<div *if>
|
||||||
|
{{foo}}-{{bar}}
|
||||||
|
<span *if>{{foo}}-{{bar}}-{{baz}}</span>
|
||||||
|
<span #bar></span>
|
||||||
|
</div>
|
||||||
|
<div #baz></div>
|
||||||
|
\`
|
||||||
|
})
|
||||||
|
export class MyComponent {}
|
||||||
|
|
||||||
|
@NgModule({declarations: [IfDirective, MyComponent]})
|
||||||
|
export class MyModule {}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const MyComponentDefinition = `
|
||||||
|
const $c1$ = ["foo", ""];
|
||||||
|
const $c2$ = ["if", ""];
|
||||||
|
const $c3$ = ["baz", ""];
|
||||||
|
const $c4$ = ["bar", ""];
|
||||||
|
function MyComponent_div_span_Template_2(rf, ctx1, ctx0, ctx) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵE(0, "span");
|
||||||
|
$r3$.ɵT(1);
|
||||||
|
$r3$.ɵe();
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
const $foo$ = $r3$.ɵr(2, 1);
|
||||||
|
const $bar$ = $r3$.ɵr(1, 4);
|
||||||
|
const $baz$ = $r3$.ɵr(2, 5);
|
||||||
|
$r3$.ɵt(1, $r3$.ɵi3("", $foo$, "-", $bar$, "-", $baz$, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function MyComponent_div_Template_3(rf, ctx0, ctx) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵE(0, "div");
|
||||||
|
$r3$.ɵT(1);
|
||||||
|
$r3$.ɵC(2, MyComponent_div_span_Template_2, null, $c2$);
|
||||||
|
$r3$.ɵEe(3, "span", null, $c4$);
|
||||||
|
$r3$.ɵe();
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
const $foo$ = $r3$.ɵr(1, 1);
|
||||||
|
const $bar$ = $r3$.ɵld(4);
|
||||||
|
$r3$.ɵt(1, $r3$.ɵi2(" ", $foo$, "-", $bar$, " "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
…
|
||||||
|
MyComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
||||||
|
type: MyComponent,
|
||||||
|
selectors: [["my-component"]],
|
||||||
|
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||||
|
template: function MyComponent_Template(rf, ctx) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵEe(0, "div", null, $c1$);
|
||||||
|
$r3$.ɵT(2);
|
||||||
|
$r3$.ɵC(3, MyComponent_div_Template_3, null, $c2$);
|
||||||
|
$r3$.ɵEe(4, "div", null, $c3$);
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
const $foo$ = $r3$.ɵld(1);
|
||||||
|
$r3$.ɵt(2, $r3$.ɵi1(" ", $foo$, " "));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
directives:[IfDirective]
|
||||||
|
});`;
|
||||||
|
|
||||||
|
const result = compile(files, angularFiles);
|
||||||
|
const source = result.source;
|
||||||
|
|
||||||
|
expectEmit(source, MyComponentDefinition, 'Incorrect MyComponent.ngComponentDef');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe('lifecycle hooks', () => {
|
describe('lifecycle hooks', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
|
@ -1361,6 +1452,14 @@ describe('compiler compliance', () => {
|
||||||
|
|
||||||
const MyComponentDefinition = `
|
const MyComponentDefinition = `
|
||||||
const $_c0$ = ["for","","forOf",""];
|
const $_c0$ = ["for","","forOf",""];
|
||||||
|
function MyComponent__svg_g_Template_1(rf, ctx0, ctx) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵNS();
|
||||||
|
$r3$.ɵE(0,"g");
|
||||||
|
$r3$.ɵEe(1,"circle");
|
||||||
|
$r3$.ɵe();
|
||||||
|
}
|
||||||
|
}
|
||||||
…
|
…
|
||||||
MyComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
MyComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
||||||
type: MyComponent,
|
type: MyComponent,
|
||||||
|
@ -1374,14 +1473,6 @@ describe('compiler compliance', () => {
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
}
|
}
|
||||||
if (rf & 2) { $r3$.ɵp(1,"forOf",$r3$.ɵb(ctx.items)); }
|
if (rf & 2) { $r3$.ɵp(1,"forOf",$r3$.ɵb(ctx.items)); }
|
||||||
function MyComponent__svg_g_Template_1(rf, ctx0) {
|
|
||||||
if (rf & 1) {
|
|
||||||
$r3$.ɵNS();
|
|
||||||
$r3$.ɵE(0,"g");
|
|
||||||
$r3$.ɵEe(1,"circle");
|
|
||||||
$r3$.ɵe();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
directives: [ForOfDirective]
|
directives: [ForOfDirective]
|
||||||
});
|
});
|
||||||
|
@ -1434,6 +1525,17 @@ describe('compiler compliance', () => {
|
||||||
|
|
||||||
const MyComponentDefinition = `
|
const MyComponentDefinition = `
|
||||||
const $_c0$ = ["for","","forOf",""];
|
const $_c0$ = ["for","","forOf",""];
|
||||||
|
function MyComponent_li_Template_1(rf, ctx0, ctx) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵE(0, "li");
|
||||||
|
$r3$.ɵT(1);
|
||||||
|
$r3$.ɵe();
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
const $item$ = ctx0.$implicit;
|
||||||
|
$r3$.ɵt(1, $r3$.ɵi1("", $item$.name, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
…
|
…
|
||||||
MyComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
MyComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
||||||
type: MyComponent,
|
type: MyComponent,
|
||||||
|
@ -1448,18 +1550,6 @@ describe('compiler compliance', () => {
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(1, "forOf", $r3$.ɵb(ctx.items));
|
$r3$.ɵp(1, "forOf", $r3$.ɵb(ctx.items));
|
||||||
}
|
}
|
||||||
|
|
||||||
function MyComponent_li_Template_1(rf, ctx0) {
|
|
||||||
if (rf & 1) {
|
|
||||||
$r3$.ɵE(0, "li");
|
|
||||||
$r3$.ɵT(1);
|
|
||||||
$r3$.ɵe();
|
|
||||||
}
|
|
||||||
if (rf & 2) {
|
|
||||||
const $item$ = ctx0.$implicit;
|
|
||||||
$r3$.ɵt(1, $r3$.ɵi1("", $item$.name, ""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
directives: [ForOfDirective]
|
directives: [ForOfDirective]
|
||||||
});
|
});
|
||||||
|
@ -1512,6 +1602,37 @@ describe('compiler compliance', () => {
|
||||||
|
|
||||||
const MyComponentDefinition = `
|
const MyComponentDefinition = `
|
||||||
const $c1$ = ["for", "", "forOf", ""];
|
const $c1$ = ["for", "", "forOf", ""];
|
||||||
|
function MyComponent_li_li_Template_4(rf, ctx1, ctx0, ctx) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵE(0, "li");
|
||||||
|
$r3$.ɵT(1);
|
||||||
|
$r3$.ɵe();
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
const $item$ = ctx0.$implicit;
|
||||||
|
const $info$ = ctx1.$implicit;
|
||||||
|
$r3$.ɵt(1, $r3$.ɵi2(" ", $item$.name, ": ", $info$.description, " "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function MyComponent_li_Template_1(rf, ctx0, ctx) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵE(0, "li");
|
||||||
|
$r3$.ɵE(1, "div");
|
||||||
|
$r3$.ɵT(2);
|
||||||
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵE(3, "ul");
|
||||||
|
$r3$.ɵC(4, MyComponent_li_li_Template_4, null, $c1$);
|
||||||
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵe();
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
const $item$ = ctx0.$implicit;
|
||||||
|
$r3$.ɵt(2, $r3$.ɵi1("", IDENT.name, ""));
|
||||||
|
$r3$.ɵp(4, "forOf", $r3$.ɵb(IDENT.infos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
…
|
…
|
||||||
MyComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
MyComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
||||||
type: MyComponent,
|
type: MyComponent,
|
||||||
|
@ -1526,37 +1647,6 @@ describe('compiler compliance', () => {
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(1, "forOf", $r3$.ɵb(ctx.items));
|
$r3$.ɵp(1, "forOf", $r3$.ɵb(ctx.items));
|
||||||
}
|
}
|
||||||
|
|
||||||
function MyComponent_li_Template_1(rf, ctx0) {
|
|
||||||
if (rf & 1) {
|
|
||||||
$r3$.ɵE(0, "li");
|
|
||||||
$r3$.ɵE(1, "div");
|
|
||||||
$r3$.ɵT(2);
|
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵE(3, "ul");
|
|
||||||
$r3$.ɵC(4, MyComponent_li_li_Template_4, null, $c1$);
|
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵe();
|
|
||||||
}
|
|
||||||
if (rf & 2) {
|
|
||||||
const $item$ = ctx0.$implicit;
|
|
||||||
$r3$.ɵt(2, $r3$.ɵi1("", IDENT.name, ""));
|
|
||||||
$r3$.ɵp(4, "forOf", $r3$.ɵb(IDENT.infos));
|
|
||||||
}
|
|
||||||
|
|
||||||
function MyComponent_li_li_Template_4(rf, ctx1) {
|
|
||||||
if (rf & 1) {
|
|
||||||
$r3$.ɵE(0, "li");
|
|
||||||
$r3$.ɵT(1);
|
|
||||||
$r3$.ɵe();
|
|
||||||
}
|
|
||||||
if (rf & 2) {
|
|
||||||
const $item$ = ctx0.$implicit;
|
|
||||||
const $info$ = ctx1.$implicit;
|
|
||||||
$r3$.ɵt(1, $r3$.ɵi2(" ", $item$.name, ": ", $info$.description, " "));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
directives: [ForOfDirective]
|
directives: [ForOfDirective]
|
||||||
});`;
|
});`;
|
||||||
|
|
|
@ -52,6 +52,49 @@ describe('compiler compliance: template', () => {
|
||||||
// The template should look like this (where IDENT is a wild card for an identifier):
|
// The template should look like this (where IDENT is a wild card for an identifier):
|
||||||
const template = `
|
const template = `
|
||||||
const $c0$ = ["ngFor","","ngForOf",""];
|
const $c0$ = ["ngFor","","ngForOf",""];
|
||||||
|
function MyComponent_ul_li_div_Template_1(rf, $ctx2$, $ctx1$, $ctx0$, $ctx$) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$i0$.ɵE(0, "div");
|
||||||
|
$i0$.ɵL("click", function MyComponent_ul_li_div_Template_1_div_click_listener($event){
|
||||||
|
const $outer$ = $ctx0$.$implicit;
|
||||||
|
const $middle$ = $ctx1$.$implicit;
|
||||||
|
const $inner$ = $ctx2$.$implicit;
|
||||||
|
return ctx.onClick($outer$, $middle$, $inner$);
|
||||||
|
});
|
||||||
|
$i0$.ɵT(1);
|
||||||
|
$i0$.ɵe();
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
const $outer$ = $ctx0$.$implicit;
|
||||||
|
const $middle$ = $ctx1$.$implicit;
|
||||||
|
const $inner$ = $ctx2$.$implicit;
|
||||||
|
$i0$.ɵp(0, "title", $i0$.ɵb(ctx.format($outer$, $middle$, $inner$, $ctx$.component)));
|
||||||
|
$i0$.ɵt(1, $i0$.ɵi1(" ", ctx.format($outer$, $middle$, $inner$, $ctx$.component), " "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function MyComponent_ul_li_Template_1(rf, $ctx1$, $ctx0$, $ctx$) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$i0$.ɵE(0, "li");
|
||||||
|
$i0$.ɵC(1, MyComponent_ul_li_div_Template_1, null, _c0);
|
||||||
|
$i0$.ɵe();
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
$i0$.ɵp(1, "ngForOf", $i0$.ɵb($ctx$.items));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function MyComponent_ul_Template_0(rf, $ctx0$, $ctx$) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$i0$.ɵE(0, "ul");
|
||||||
|
$i0$.ɵC(1, MyComponent_ul_li_Template_1, null, _c0);
|
||||||
|
$i0$.ɵe();
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
const $outer$ = $ctx0$.$implicit;
|
||||||
|
$i0$.ɵp(1, "ngForOf", $i0$.ɵb($outer$.items));
|
||||||
|
}
|
||||||
|
}
|
||||||
// ...
|
// ...
|
||||||
template:function MyComponent_Template(rf, $ctx$){
|
template:function MyComponent_Template(rf, $ctx$){
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
|
@ -60,48 +103,6 @@ describe('compiler compliance: template', () => {
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$i0$.ɵp(0, "ngForOf", $i0$.ɵb($ctx$.items));
|
$i0$.ɵp(0, "ngForOf", $i0$.ɵb($ctx$.items));
|
||||||
}
|
}
|
||||||
|
|
||||||
function MyComponent_ul_Template_0(rf, $ctx0$) {
|
|
||||||
if (rf & 1) {
|
|
||||||
$i0$.ɵE(0, "ul");
|
|
||||||
$i0$.ɵC(1, MyComponent_ul_li_Template_1, null, _c0);
|
|
||||||
$i0$.ɵe();
|
|
||||||
}
|
|
||||||
if (rf & 2) {
|
|
||||||
const $outer$ = $ctx0$.$implicit;
|
|
||||||
$i0$.ɵp(1, "ngForOf", $i0$.ɵb($outer$.items));
|
|
||||||
}
|
|
||||||
function MyComponent_ul_li_Template_1(rf, $ctx1$) {
|
|
||||||
if (rf & 1) {
|
|
||||||
$i0$.ɵE(0, "li");
|
|
||||||
$i0$.ɵC(1, MyComponent_ul_li_div_Template_1, null, _c0);
|
|
||||||
$i0$.ɵe();
|
|
||||||
}
|
|
||||||
if (rf & 2) {
|
|
||||||
$i0$.ɵp(1, "ngForOf", $i0$.ɵb($ctx$.items));
|
|
||||||
}
|
|
||||||
function MyComponent_ul_li_div_Template_1(rf, $ctx2$) {
|
|
||||||
if (rf & 1) {
|
|
||||||
$i0$.ɵE(0, "div");
|
|
||||||
$i0$.ɵL("click", function MyComponent_ul_li_div_Template_1_div_click_listener($event){
|
|
||||||
const $outer$ = $ctx0$.$implicit;
|
|
||||||
const $middle$ = $ctx1$.$implicit;
|
|
||||||
const $inner$ = $ctx2$.$implicit;
|
|
||||||
return ctx.onClick($outer$, $middle$, $inner$);
|
|
||||||
});
|
|
||||||
$i0$.ɵT(1);
|
|
||||||
$i0$.ɵe();
|
|
||||||
}
|
|
||||||
if (rf & 2) {
|
|
||||||
const $outer$ = $ctx0$.$implicit;
|
|
||||||
const $middle$ = $ctx1$.$implicit;
|
|
||||||
const $inner$ = $ctx2$.$implicit;
|
|
||||||
$i0$.ɵp(0, "title", $i0$.ɵb(ctx.format($outer$, $middle$, $inner$, $ctx$.component)));
|
|
||||||
$i0$.ɵt(1, $i0$.ɵi1(" ", ctx.format($outer$, $middle$, $inner$, $ctx$.component), " "));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
const result = compile(files, angularFiles);
|
const result = compile(files, angularFiles);
|
||||||
|
|
|
@ -87,6 +87,8 @@ export class Identifiers {
|
||||||
static projection: o.ExternalReference = {name: 'ɵP', moduleName: CORE};
|
static projection: o.ExternalReference = {name: 'ɵP', moduleName: CORE};
|
||||||
static projectionDef: o.ExternalReference = {name: 'ɵpD', moduleName: CORE};
|
static projectionDef: o.ExternalReference = {name: 'ɵpD', moduleName: CORE};
|
||||||
|
|
||||||
|
static reference: o.ExternalReference = {name: 'ɵr', moduleName: CORE};
|
||||||
|
|
||||||
static inject: o.ExternalReference = {name: 'inject', moduleName: CORE};
|
static inject: o.ExternalReference = {name: 'inject', moduleName: CORE};
|
||||||
|
|
||||||
static injectAttribute: o.ExternalReference = {name: 'ɵinjectAttribute', moduleName: CORE};
|
static injectAttribute: o.ExternalReference = {name: 'ɵinjectAttribute', moduleName: CORE};
|
||||||
|
|
|
@ -58,8 +58,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
private _prefixCode: o.Statement[] = [];
|
private _prefixCode: o.Statement[] = [];
|
||||||
private _creationCode: o.Statement[] = [];
|
private _creationCode: o.Statement[] = [];
|
||||||
private _variableCode: o.Statement[] = [];
|
private _variableCode: o.Statement[] = [];
|
||||||
private _bindingCode: o.Statement[] = [];
|
private _bindingCode: (() => o.Statement)[] = [];
|
||||||
private _postfixCode: o.Statement[] = [];
|
private _nestedTemplates: (() => void)[] = [];
|
||||||
private _valueConverter: ValueConverter;
|
private _valueConverter: ValueConverter;
|
||||||
private _unsupported = unsupported;
|
private _unsupported = unsupported;
|
||||||
private _bindingScope: BindingScope;
|
private _bindingScope: BindingScope;
|
||||||
|
@ -84,9 +84,9 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
// function)
|
// function)
|
||||||
this._dataIndex = viewQueries.length;
|
this._dataIndex = viewQueries.length;
|
||||||
this._bindingScope =
|
this._bindingScope =
|
||||||
parentBindingScope.nestedScope((lhsVar: o.ReadVarExpr, expression: o.Expression) => {
|
parentBindingScope.nestedScope(level, (lhsVar: o.ReadVarExpr, rhsExpr: o.Expression) => {
|
||||||
this._bindingCode.push(
|
this._variableCode.push(
|
||||||
lhsVar.set(expression).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
lhsVar.set(rhsExpr).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
||||||
});
|
});
|
||||||
this._valueConverter = new ValueConverter(
|
this._valueConverter = new ValueConverter(
|
||||||
constantPool, () => this.allocateDataSlot(),
|
constantPool, () => this.allocateDataSlot(),
|
||||||
|
@ -106,7 +106,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
nodes: t.Node[], variables: t.Variable[], hasNgContent: boolean = false,
|
nodes: t.Node[], variables: t.Variable[], hasNgContent: boolean = false,
|
||||||
ngContentSelectors: string[] = []): o.FunctionExpr {
|
ngContentSelectors: string[] = []): o.FunctionExpr {
|
||||||
if (this._namespace !== R3.namespaceHTML) {
|
if (this._namespace !== R3.namespaceHTML) {
|
||||||
this.instruction(this._creationCode, null, this._namespace);
|
this.creationInstruction(null, this._namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create variable bindings
|
// Create variable bindings
|
||||||
|
@ -132,24 +132,24 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
parameters.push(parsed, unParsed);
|
parameters.push(parsed, unParsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.instruction(this._creationCode, null, R3.projectionDef, ...parameters);
|
this.creationInstruction(null, R3.projectionDef, ...parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
t.visitAll(this, nodes);
|
t.visitAll(this, nodes);
|
||||||
|
|
||||||
if (this._pureFunctionSlots > 0) {
|
|
||||||
this.instruction(
|
|
||||||
this._creationCode, null, R3.reserveSlots, o.literal(this._pureFunctionSlots));
|
|
||||||
}
|
|
||||||
|
|
||||||
const creationCode = this._creationCode.length > 0 ?
|
const creationCode = this._creationCode.length > 0 ?
|
||||||
[renderFlagCheckIfStmt(core.RenderFlags.Create, this._creationCode)] :
|
[renderFlagCheckIfStmt(core.RenderFlags.Create, this._creationCode)] :
|
||||||
[];
|
[];
|
||||||
|
|
||||||
const updateCode = this._bindingCode.length > 0 ?
|
const updateCode = this._bindingCode.length > 0 ?
|
||||||
[renderFlagCheckIfStmt(core.RenderFlags.Update, this._bindingCode)] :
|
[renderFlagCheckIfStmt(core.RenderFlags.Update, this._variableCode.concat(
|
||||||
|
this._variableCode.concat(this._bindingCode.map((fn: () => o.Statement) => fn()))))] :
|
||||||
[];
|
[];
|
||||||
|
|
||||||
|
if (this._pureFunctionSlots > 0) {
|
||||||
|
this.creationInstruction(null, R3.reserveSlots, o.literal(this._pureFunctionSlots));
|
||||||
|
}
|
||||||
|
|
||||||
// Generate maps of placeholder name to node indexes
|
// Generate maps of placeholder name to node indexes
|
||||||
// TODO(vicb): This is a WIP, not fully supported yet
|
// TODO(vicb): This is a WIP, not fully supported yet
|
||||||
for (const phToNodeIdx of this._phToNodeIdxes) {
|
for (const phToNodeIdx of this._phToNodeIdxes) {
|
||||||
|
@ -163,19 +163,21 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._nestedTemplates.forEach(buildTemplateFn => buildTemplateFn());
|
||||||
|
|
||||||
return o.fn(
|
return o.fn(
|
||||||
[new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(this.contextParameter, null)],
|
// i.e. (rf: RenderFlags, ctx0: any, ctx: any)
|
||||||
|
[
|
||||||
|
new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), ...this.getNestedContexts(),
|
||||||
|
new o.FnParam(CONTEXT_NAME, null)
|
||||||
|
],
|
||||||
[
|
[
|
||||||
// Temporary variable declarations for query refresh (i.e. let _t: any;)
|
// Temporary variable declarations for query refresh (i.e. let _t: any;)
|
||||||
...this._prefixCode,
|
...this._prefixCode,
|
||||||
// Creating mode (i.e. if (rf & RenderFlags.Create) { ... })
|
// Creating mode (i.e. if (rf & RenderFlags.Create) { ... })
|
||||||
...creationCode,
|
...creationCode,
|
||||||
// Temporary variable declarations for local refs (i.e. const tmp = ld(1) as any)
|
|
||||||
...this._variableCode,
|
|
||||||
// Binding and refresh mode (i.e. if (rf & RenderFlags.Update) {...})
|
// Binding and refresh mode (i.e. if (rf & RenderFlags.Update) {...})
|
||||||
...updateCode,
|
...updateCode,
|
||||||
// Nested templates (i.e. function CompTemplate() {})
|
|
||||||
...this._postfixCode
|
|
||||||
],
|
],
|
||||||
o.INFERRED_TYPE, null, this.templateName);
|
o.INFERRED_TYPE, null, this.templateName);
|
||||||
}
|
}
|
||||||
|
@ -203,7 +205,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
parameters.push(o.literal(selectorIndex));
|
parameters.push(o.literal(selectorIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.instruction(this._creationCode, ngContent.sourceSpan, R3.projection, ...parameters);
|
this.creationInstruction(ngContent.sourceSpan, R3.projection, ...parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -220,12 +222,23 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
|
|
||||||
addNamespaceInstruction(nsInstruction: o.ExternalReference, element: t.Element) {
|
addNamespaceInstruction(nsInstruction: o.ExternalReference, element: t.Element) {
|
||||||
this._namespace = nsInstruction;
|
this._namespace = nsInstruction;
|
||||||
this.instruction(this._creationCode, element.sourceSpan, nsInstruction);
|
this.creationInstruction(element.sourceSpan, nsInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
getNestedContexts(): o.FnParam[] {
|
||||||
|
const nestedContexts = [];
|
||||||
|
let nestingLevel = this.level - 1;
|
||||||
|
|
||||||
|
while (nestingLevel >= 0) {
|
||||||
|
nestedContexts.push(new o.FnParam(`ctx${nestingLevel}`, null));
|
||||||
|
nestingLevel--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nestedContexts;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitElement(element: t.Element) {
|
visitElement(element: t.Element) {
|
||||||
const elementIndex = this.allocateDataSlot();
|
const elementIndex = this.allocateDataSlot();
|
||||||
const referenceDataSlots = new Map<string, number>();
|
|
||||||
const wasInI18nSection = this._inI18nSection;
|
const wasInI18nSection = this._inI18nSection;
|
||||||
|
|
||||||
const outputAttrs: {[name: string]: string} = {};
|
const outputAttrs: {[name: string]: string} = {};
|
||||||
|
@ -412,13 +425,19 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
if (element.references && element.references.length > 0) {
|
if (element.references && element.references.length > 0) {
|
||||||
const references = flatten(element.references.map(reference => {
|
const references = flatten(element.references.map(reference => {
|
||||||
const slot = this.allocateDataSlot();
|
const slot = this.allocateDataSlot();
|
||||||
referenceDataSlots.set(reference.name, slot);
|
|
||||||
// Generate the update temporary.
|
// Generate the update temporary.
|
||||||
const variableName = this._bindingScope.freshReferenceName();
|
const variableName = this._bindingScope.freshReferenceName();
|
||||||
this._variableCode.push(o.variable(variableName, o.INFERRED_TYPE)
|
// When the ref's binding is processed, we'll either generate a load() or a reference()
|
||||||
.set(o.importExpr(R3.load).callFn([o.literal(slot)]))
|
// instruction depending on the nesting level of the binding relative to the reference def.
|
||||||
.toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
const refLevel = this.level;
|
||||||
this._bindingScope.set(reference.name, o.variable(variableName));
|
this._bindingScope.set(
|
||||||
|
reference.name, o.variable(variableName), undefined, (bindingLevel: number) => {
|
||||||
|
return bindingLevel === refLevel ?
|
||||||
|
o.importExpr(R3.load).callFn([o.literal(slot)]) :
|
||||||
|
o.importExpr(R3.reference).callFn([
|
||||||
|
o.literal(bindingLevel - refLevel), o.literal(slot)
|
||||||
|
]);
|
||||||
|
});
|
||||||
return [reference.name, reference.value];
|
return [reference.name, reference.value];
|
||||||
}));
|
}));
|
||||||
parameters.push(this.constantPool.getConstLiteral(asLiteral(references), true));
|
parameters.push(this.constantPool.getConstLiteral(asLiteral(references), true));
|
||||||
|
@ -446,16 +465,14 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
!hasStylingInstructions && element.children.length === 0 && element.outputs.length === 0;
|
!hasStylingInstructions && element.children.length === 0 && element.outputs.length === 0;
|
||||||
|
|
||||||
if (createSelfClosingInstruction) {
|
if (createSelfClosingInstruction) {
|
||||||
this.instruction(
|
this.creationInstruction(element.sourceSpan, R3.element, ...trimTrailingNulls(parameters));
|
||||||
this._creationCode, element.sourceSpan, R3.element, ...trimTrailingNulls(parameters));
|
|
||||||
} else {
|
} else {
|
||||||
// Generate the instruction create element instruction
|
// Generate the instruction create element instruction
|
||||||
if (i18nMessages.length > 0) {
|
if (i18nMessages.length > 0) {
|
||||||
this._creationCode.push(...i18nMessages);
|
this._creationCode.push(...i18nMessages);
|
||||||
}
|
}
|
||||||
this.instruction(
|
this.creationInstruction(
|
||||||
this._creationCode, element.sourceSpan, R3.elementStart,
|
element.sourceSpan, R3.elementStart, ...trimTrailingNulls(parameters));
|
||||||
...trimTrailingNulls(parameters));
|
|
||||||
|
|
||||||
// initial styling for static style="..." attributes
|
// initial styling for static style="..." attributes
|
||||||
if (hasStylingInstructions) {
|
if (hasStylingInstructions) {
|
||||||
|
@ -499,8 +516,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
const evName = sanitizeIdentifier(outputAst.name);
|
const evName = sanitizeIdentifier(outputAst.name);
|
||||||
const functionName = `${this.templateName}_${elName}_${evName}_listener`;
|
const functionName = `${this.templateName}_${elName}_${evName}_listener`;
|
||||||
const localVars: o.Statement[] = [];
|
const localVars: o.Statement[] = [];
|
||||||
const bindingScope =
|
const bindingScope = this._bindingScope.nestedScope(
|
||||||
this._bindingScope.nestedScope((lhsVar: o.ReadVarExpr, rhsExpression: o.Expression) => {
|
this.level + 1, (lhsVar: o.ReadVarExpr, rhsExpression: o.Expression) => {
|
||||||
localVars.push(
|
localVars.push(
|
||||||
lhsVar.set(rhsExpression).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
lhsVar.set(rhsExpression).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
||||||
});
|
});
|
||||||
|
@ -510,9 +527,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
const handler = o.fn(
|
const handler = o.fn(
|
||||||
[new o.FnParam('$event', o.DYNAMIC_TYPE)], [...localVars, ...bindingExpr.render3Stmts],
|
[new o.FnParam('$event', o.DYNAMIC_TYPE)], [...localVars, ...bindingExpr.render3Stmts],
|
||||||
o.INFERRED_TYPE, null, functionName);
|
o.INFERRED_TYPE, null, functionName);
|
||||||
this.instruction(
|
this.creationInstruction(
|
||||||
this._creationCode, outputAst.sourceSpan, R3.listener, o.literal(outputAst.name),
|
outputAst.sourceSpan, R3.listener, o.literal(outputAst.name), handler);
|
||||||
handler);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,17 +544,21 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
const stylingInput = mapBasedStyleInput || mapBasedClassInput;
|
const stylingInput = mapBasedStyleInput || mapBasedClassInput;
|
||||||
if (stylingInput) {
|
if (stylingInput) {
|
||||||
const params: o.Expression[] = [];
|
const params: o.Expression[] = [];
|
||||||
|
let value: AST;
|
||||||
if (mapBasedClassInput) {
|
if (mapBasedClassInput) {
|
||||||
params.push(this.convertPropertyBinding(implicit, mapBasedClassInput.value, true));
|
value = mapBasedClassInput.value.visit(this._valueConverter);
|
||||||
} else if (mapBasedStyleInput) {
|
} else if (mapBasedStyleInput) {
|
||||||
params.push(o.NULL_EXPR);
|
params.push(o.NULL_EXPR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mapBasedStyleInput) {
|
if (mapBasedStyleInput) {
|
||||||
params.push(this.convertPropertyBinding(implicit, mapBasedStyleInput.value, true));
|
value = mapBasedStyleInput.value.visit(this._valueConverter);
|
||||||
}
|
}
|
||||||
this.instruction(
|
|
||||||
this._bindingCode, stylingInput.sourceSpan, R3.elementStylingMap, indexLiteral,
|
this.updateInstruction(stylingInput.sourceSpan, R3.elementStylingMap, () => {
|
||||||
...params);
|
params.push(this.convertPropertyBinding(implicit, value, true));
|
||||||
|
return [indexLiteral, ...params];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let lastInputCommand: t.BoundAttribute|null = null;
|
let lastInputCommand: t.BoundAttribute|null = null;
|
||||||
|
@ -546,18 +566,19 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
let i = mapBasedStyleInput ? 1 : 0;
|
let i = mapBasedStyleInput ? 1 : 0;
|
||||||
for (i; i < styleInputs.length; i++) {
|
for (i; i < styleInputs.length; i++) {
|
||||||
const input = styleInputs[i];
|
const input = styleInputs[i];
|
||||||
const convertedBinding = this.convertPropertyBinding(implicit, input.value, true);
|
const params: any[] = [];
|
||||||
const params = [convertedBinding];
|
|
||||||
const sanitizationRef = resolveSanitizationFn(input, input.securityContext);
|
const sanitizationRef = resolveSanitizationFn(input, input.securityContext);
|
||||||
if (sanitizationRef) {
|
if (sanitizationRef) params.push(sanitizationRef);
|
||||||
params.push(sanitizationRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
const key = input.name;
|
const key = input.name;
|
||||||
const styleIndex: number = stylesIndexMap[key] !;
|
const styleIndex: number = stylesIndexMap[key] !;
|
||||||
this.instruction(
|
const value = input.value.visit(this._valueConverter);
|
||||||
this._bindingCode, input.sourceSpan, R3.elementStyleProp, indexLiteral,
|
this.updateInstruction(input.sourceSpan, R3.elementStyleProp, () => {
|
||||||
o.literal(styleIndex), ...params);
|
return [
|
||||||
|
indexLiteral, o.literal(styleIndex),
|
||||||
|
this.convertPropertyBinding(implicit, value, true), ...params
|
||||||
|
];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
lastInputCommand = styleInputs[styleInputs.length - 1];
|
lastInputCommand = styleInputs[styleInputs.length - 1];
|
||||||
|
@ -567,25 +588,26 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
let i = mapBasedClassInput ? 1 : 0;
|
let i = mapBasedClassInput ? 1 : 0;
|
||||||
for (i; i < classInputs.length; i++) {
|
for (i; i < classInputs.length; i++) {
|
||||||
const input = classInputs[i];
|
const input = classInputs[i];
|
||||||
const convertedBinding = this.convertPropertyBinding(implicit, input.value, true);
|
const params: any[] = [];
|
||||||
const params = [convertedBinding];
|
|
||||||
const sanitizationRef = resolveSanitizationFn(input, input.securityContext);
|
const sanitizationRef = resolveSanitizationFn(input, input.securityContext);
|
||||||
if (sanitizationRef) {
|
if (sanitizationRef) params.push(sanitizationRef);
|
||||||
params.push(sanitizationRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
const key = input.name;
|
const key = input.name;
|
||||||
const classIndex: number = classesIndexMap[key] !;
|
const classIndex: number = classesIndexMap[key] !;
|
||||||
this.instruction(
|
const value = input.value.visit(this._valueConverter);
|
||||||
this._bindingCode, input.sourceSpan, R3.elementClassProp, indexLiteral,
|
this.updateInstruction(input.sourceSpan, R3.elementClassProp, () => {
|
||||||
o.literal(classIndex), ...params);
|
return [
|
||||||
|
indexLiteral, o.literal(classIndex),
|
||||||
|
this.convertPropertyBinding(implicit, value, true), ...params
|
||||||
|
];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
lastInputCommand = classInputs[classInputs.length - 1];
|
lastInputCommand = classInputs[classInputs.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.instruction(
|
this.updateInstruction(
|
||||||
this._bindingCode, lastInputCommand !.sourceSpan, R3.elementStylingApply, indexLiteral);
|
lastInputCommand !.sourceSpan, R3.elementStylingApply, () => [indexLiteral]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate element input bindings
|
// Generate element input bindings
|
||||||
|
@ -595,20 +617,20 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const convertedBinding = this.convertPropertyBinding(implicit, input.value);
|
|
||||||
|
|
||||||
const instruction = mapBindingToInstruction(input.type);
|
const instruction = mapBindingToInstruction(input.type);
|
||||||
if (instruction) {
|
if (instruction) {
|
||||||
const params = [convertedBinding];
|
const params: any[] = [];
|
||||||
const sanitizationRef = resolveSanitizationFn(input, input.securityContext);
|
const sanitizationRef = resolveSanitizationFn(input, input.securityContext);
|
||||||
if (sanitizationRef) {
|
if (sanitizationRef) params.push(sanitizationRef);
|
||||||
params.push(sanitizationRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(chuckj): runtime: security context?
|
// TODO(chuckj): runtime: security context?
|
||||||
this.instruction(
|
const value = input.value.visit(this._valueConverter);
|
||||||
this._bindingCode, input.sourceSpan, instruction, o.literal(elementIndex),
|
this.updateInstruction(input.sourceSpan, instruction, () => {
|
||||||
o.literal(input.name), ...params);
|
return [
|
||||||
|
o.literal(elementIndex), o.literal(input.name),
|
||||||
|
this.convertPropertyBinding(implicit, value), ...params
|
||||||
|
];
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this._unsupported(`binding type ${input.type}`);
|
this._unsupported(`binding type ${input.type}`);
|
||||||
}
|
}
|
||||||
|
@ -625,8 +647,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
|
|
||||||
if (!createSelfClosingInstruction) {
|
if (!createSelfClosingInstruction) {
|
||||||
// Finish element construction mode.
|
// Finish element construction mode.
|
||||||
this.instruction(
|
this.creationInstruction(element.endSourceSpan || element.sourceSpan, R3.elementEnd);
|
||||||
this._creationCode, element.endSourceSpan || element.sourceSpan, R3.elementEnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore the state before exiting this node
|
// Restore the state before exiting this node
|
||||||
|
@ -675,17 +696,19 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
// e.g. C(1, C1Template)
|
// e.g. C(1, C1Template)
|
||||||
this.instruction(
|
this.creationInstruction(
|
||||||
this._creationCode, template.sourceSpan, R3.containerCreate,
|
template.sourceSpan, R3.containerCreate, ...trimTrailingNulls(parameters));
|
||||||
...trimTrailingNulls(parameters));
|
|
||||||
|
|
||||||
// e.g. p(1, 'forOf', ɵb(ctx.items));
|
// e.g. p(1, 'forOf', ɵb(ctx.items));
|
||||||
const context = o.variable(CONTEXT_NAME);
|
const context = o.variable(CONTEXT_NAME);
|
||||||
template.inputs.forEach(input => {
|
template.inputs.forEach(input => {
|
||||||
const convertedBinding = this.convertPropertyBinding(context, input.value);
|
const value = input.value.visit(this._valueConverter);
|
||||||
this.instruction(
|
this.updateInstruction(template.sourceSpan, R3.elementProperty, () => {
|
||||||
this._bindingCode, template.sourceSpan, R3.elementProperty, o.literal(templateIndex),
|
return [
|
||||||
o.literal(input.name), convertedBinding);
|
o.literal(templateIndex), o.literal(input.name),
|
||||||
|
this.convertPropertyBinding(context, value)
|
||||||
|
];
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create the template function
|
// Create the template function
|
||||||
|
@ -693,9 +716,16 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
this.constantPool, templateContext, this._bindingScope, this.level + 1, contextName,
|
this.constantPool, templateContext, this._bindingScope, this.level + 1, contextName,
|
||||||
templateName, [], this.directiveMatcher, this.directives, this.pipeTypeByName, this.pipes,
|
templateName, [], this.directiveMatcher, this.directives, this.pipeTypeByName, this.pipes,
|
||||||
this._namespace);
|
this._namespace);
|
||||||
const templateFunctionExpr =
|
|
||||||
templateVisitor.buildTemplateFunction(template.children, template.variables);
|
// Nested templates must not be visited until after their parent templates have completed
|
||||||
this._postfixCode.push(templateFunctionExpr.toDeclStmt(templateName, null));
|
// processing, so they are queued here until after the initial pass. Otherwise, we wouldn't
|
||||||
|
// be able to support bindings in nested templates to local refs that occur after the
|
||||||
|
// template definition. e.g. <div *ngIf="showing"> {{ foo }} </div> <div #foo></div>
|
||||||
|
this._nestedTemplates.push(() => {
|
||||||
|
const templateFunctionExpr =
|
||||||
|
templateVisitor.buildTemplateFunction(template.children, template.variables);
|
||||||
|
this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(templateName, null));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// These should be handled in the template or element directly.
|
// These should be handled in the template or element directly.
|
||||||
|
@ -708,17 +738,17 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
visitBoundText(text: t.BoundText) {
|
visitBoundText(text: t.BoundText) {
|
||||||
const nodeIndex = this.allocateDataSlot();
|
const nodeIndex = this.allocateDataSlot();
|
||||||
|
|
||||||
this.instruction(this._creationCode, text.sourceSpan, R3.text, o.literal(nodeIndex));
|
this.creationInstruction(text.sourceSpan, R3.text, o.literal(nodeIndex));
|
||||||
|
|
||||||
this.instruction(
|
const value = text.value.visit(this._valueConverter);
|
||||||
this._bindingCode, text.sourceSpan, R3.textBinding, o.literal(nodeIndex),
|
this.updateInstruction(
|
||||||
this.convertPropertyBinding(o.variable(CONTEXT_NAME), text.value));
|
text.sourceSpan, R3.textBinding,
|
||||||
|
() => [o.literal(nodeIndex), this.convertPropertyBinding(o.variable(CONTEXT_NAME), value)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitText(text: t.Text) {
|
visitText(text: t.Text) {
|
||||||
this.instruction(
|
this.creationInstruction(
|
||||||
this._creationCode, text.sourceSpan, R3.text, o.literal(this.allocateDataSlot()),
|
text.sourceSpan, R3.text, o.literal(this.allocateDataSlot()), o.literal(text.value));
|
||||||
o.literal(text.value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the content of the element is a single text node the translation can be inlined:
|
// When the content of the element is a single text node the translation can be inlined:
|
||||||
|
@ -736,36 +766,45 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
visitSingleI18nTextChild(text: t.Text, i18nMeta: string) {
|
visitSingleI18nTextChild(text: t.Text, i18nMeta: string) {
|
||||||
const meta = parseI18nMeta(i18nMeta);
|
const meta = parseI18nMeta(i18nMeta);
|
||||||
const variable = this.constantPool.getTranslation(text.value, meta);
|
const variable = this.constantPool.getTranslation(text.value, meta);
|
||||||
this.instruction(
|
this.creationInstruction(
|
||||||
this._creationCode, text.sourceSpan, R3.text, o.literal(this.allocateDataSlot()), variable);
|
text.sourceSpan, R3.text, o.literal(this.allocateDataSlot()), variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private allocateDataSlot() { return this._dataIndex++; }
|
private allocateDataSlot() { return this._dataIndex++; }
|
||||||
private bindingContext() { return `${this._bindingContext++}`; }
|
private bindingContext() { return `${this._bindingContext++}`; }
|
||||||
|
|
||||||
private instruction(
|
private instruction(
|
||||||
statements: o.Statement[], span: ParseSourceSpan|null, reference: o.ExternalReference,
|
span: ParseSourceSpan|null, reference: o.ExternalReference,
|
||||||
...params: o.Expression[]) {
|
params: o.Expression[]): o.Statement {
|
||||||
statements.push(o.importExpr(reference, null, span).callFn(params, span).toStmt());
|
return o.importExpr(reference, null, span).callFn(params, span).toStmt();
|
||||||
|
}
|
||||||
|
|
||||||
|
private creationInstruction(
|
||||||
|
span: ParseSourceSpan|null, reference: o.ExternalReference, ...params: o.Expression[]) {
|
||||||
|
this._creationCode.push(this.instruction(span, reference, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bindings must only be resolved after all local refs have been visited, so update mode
|
||||||
|
// instructions are queued in callbacks that execute once the initial pass has completed.
|
||||||
|
// Otherwise, we wouldn't be able to support local refs that are defined after their
|
||||||
|
// bindings. e.g. {{ foo }} <div #foo></div>
|
||||||
|
private updateInstruction(
|
||||||
|
span: ParseSourceSpan|null, reference: o.ExternalReference, paramsFn: () => o.Expression[]) {
|
||||||
|
this._bindingCode.push(() => { return this.instruction(span, reference, paramsFn()); });
|
||||||
}
|
}
|
||||||
|
|
||||||
private convertPropertyBinding(implicit: o.Expression, value: AST, skipBindFn?: boolean):
|
private convertPropertyBinding(implicit: o.Expression, value: AST, skipBindFn?: boolean):
|
||||||
o.Expression {
|
o.Expression {
|
||||||
const pipesConvertedValue = value.visit(this._valueConverter);
|
const interpolationFn =
|
||||||
if (pipesConvertedValue instanceof Interpolation) {
|
value instanceof Interpolation ? interpolate : () => error('Unexpected interpolation');
|
||||||
const convertedPropertyBinding = convertPropertyBinding(
|
|
||||||
this, implicit, pipesConvertedValue, this.bindingContext(), BindingForm.TrySimple,
|
const convertedPropertyBinding = convertPropertyBinding(
|
||||||
interpolate);
|
this, implicit, value, this.bindingContext(), BindingForm.TrySimple, interpolationFn);
|
||||||
this._bindingCode.push(...convertedPropertyBinding.stmts);
|
this._variableCode.push(...convertedPropertyBinding.stmts);
|
||||||
return convertedPropertyBinding.currValExpr;
|
|
||||||
} else {
|
const valExpr = convertedPropertyBinding.currValExpr;
|
||||||
const convertedPropertyBinding = convertPropertyBinding(
|
return value instanceof Interpolation || skipBindFn ? valExpr :
|
||||||
this, implicit, pipesConvertedValue, this.bindingContext(), BindingForm.TrySimple,
|
o.importExpr(R3.bind).callFn([valExpr]);
|
||||||
() => error('Unexpected interpolation'));
|
|
||||||
this._bindingCode.push(...convertedPropertyBinding.stmts);
|
|
||||||
const valExpr = convertedPropertyBinding.currValExpr;
|
|
||||||
return skipBindFn ? valExpr : o.importExpr(R3.bind).callFn([valExpr]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -897,6 +936,7 @@ export class BindingScope implements LocalResolver {
|
||||||
lhs: o.ReadVarExpr;
|
lhs: o.ReadVarExpr;
|
||||||
rhs: o.Expression|undefined;
|
rhs: o.Expression|undefined;
|
||||||
declared: boolean;
|
declared: boolean;
|
||||||
|
rhsCallback?: (level: number) => o.Expression;
|
||||||
}
|
}
|
||||||
> ();
|
> ();
|
||||||
private referenceNameIndex = 0;
|
private referenceNameIndex = 0;
|
||||||
|
@ -904,7 +944,7 @@ export class BindingScope implements LocalResolver {
|
||||||
static ROOT_SCOPE = new BindingScope().set('$event', o.variable('$event'));
|
static ROOT_SCOPE = new BindingScope().set('$event', o.variable('$event'));
|
||||||
|
|
||||||
private constructor(
|
private constructor(
|
||||||
private parent: BindingScope|null = null,
|
private level: number = 0, private parent: BindingScope|null = null,
|
||||||
private declareLocalVarCallback: DeclareLocalVarCallback = noop) {}
|
private declareLocalVarCallback: DeclareLocalVarCallback = noop) {}
|
||||||
|
|
||||||
get(name: string): o.Expression|null {
|
get(name: string): o.Expression|null {
|
||||||
|
@ -914,14 +954,15 @@ export class BindingScope implements LocalResolver {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (current !== this) {
|
if (current !== this) {
|
||||||
// make a local copy and reset the `declared` state.
|
// make a local copy and reset the `declared` state.
|
||||||
value = {lhs: value.lhs, rhs: value.rhs, declared: false};
|
value = {lhs: value.lhs, rhs: value.rhs, rhsCallback: value.rhsCallback, declared: false};
|
||||||
// Cache the value locally.
|
// Cache the value locally.
|
||||||
this.map.set(name, value);
|
this.map.set(name, value);
|
||||||
}
|
}
|
||||||
if (value.rhs && !value.declared) {
|
const rhs = value.rhs || value.rhsCallback && value.rhsCallback(this.level);
|
||||||
|
if (rhs && !value.declared) {
|
||||||
// if it is first time we are referencing the variable in the scope
|
// if it is first time we are referencing the variable in the scope
|
||||||
// than invoke the callback to insert variable declaration.
|
// then invoke the callback to insert variable declaration.
|
||||||
this.declareLocalVarCallback(value.lhs, value.rhs);
|
this.declareLocalVarCallback(value.lhs, rhs);
|
||||||
value.declared = true;
|
value.declared = true;
|
||||||
}
|
}
|
||||||
return value.lhs;
|
return value.lhs;
|
||||||
|
@ -940,17 +981,18 @@ export class BindingScope implements LocalResolver {
|
||||||
* `undefined` for variable that are ambient such as `$event` and which don't have `rhs`
|
* `undefined` for variable that are ambient such as `$event` and which don't have `rhs`
|
||||||
* declaration.
|
* declaration.
|
||||||
*/
|
*/
|
||||||
set(name: string, lhs: o.ReadVarExpr, rhs?: o.Expression): BindingScope {
|
set(name: string, lhs: o.ReadVarExpr, rhs?: o.Expression,
|
||||||
|
rhsCallback?: (level: number) => o.Expression): BindingScope {
|
||||||
!this.map.has(name) ||
|
!this.map.has(name) ||
|
||||||
error(`The name ${name} is already defined in scope to be ${this.map.get(name)}`);
|
error(`The name ${name} is already defined in scope to be ${this.map.get(name)}`);
|
||||||
this.map.set(name, {lhs: lhs, rhs: rhs, declared: false});
|
this.map.set(name, {lhs: lhs, rhs: rhs, declared: false, rhsCallback: rhsCallback});
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
getLocal(name: string): (o.Expression|null) { return this.get(name); }
|
getLocal(name: string): (o.Expression|null) { return this.get(name); }
|
||||||
|
|
||||||
nestedScope(declareCallback: DeclareLocalVarCallback): BindingScope {
|
nestedScope(level: number, declareCallback: DeclareLocalVarCallback): BindingScope {
|
||||||
return new BindingScope(this, declareCallback);
|
return new BindingScope(level, this, declareCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
freshReferenceName(): string {
|
freshReferenceName(): string {
|
||||||
|
|
|
@ -76,6 +76,7 @@ export {
|
||||||
e as ɵe,
|
e as ɵe,
|
||||||
p as ɵp,
|
p as ɵp,
|
||||||
pD as ɵpD,
|
pD as ɵpD,
|
||||||
|
r as ɵr,
|
||||||
rS as ɵrS,
|
rS as ɵrS,
|
||||||
a as ɵa,
|
a as ɵa,
|
||||||
s as ɵs,
|
s as ɵs,
|
||||||
|
|
|
@ -24,7 +24,7 @@ import {LInjector} from './interfaces/injector';
|
||||||
import {AttributeMarker, LContainerNode, LElementNode, LNode, LViewNode, TContainerNode, TElementNode, TNodeFlags, TNodeType} from './interfaces/node';
|
import {AttributeMarker, LContainerNode, LElementNode, LNode, LViewNode, TContainerNode, TElementNode, TNodeFlags, TNodeType} from './interfaces/node';
|
||||||
import {LQueries, QueryReadType} from './interfaces/query';
|
import {LQueries, QueryReadType} from './interfaces/query';
|
||||||
import {Renderer3} from './interfaces/renderer';
|
import {Renderer3} from './interfaces/renderer';
|
||||||
import {DECLARATION_PARENT, DIRECTIVES, HOST_NODE, INJECTOR, LViewData, QUERIES, RENDERER, TVIEW, TView} from './interfaces/view';
|
import {DECLARATION_VIEW, DIRECTIVES, HOST_NODE, INJECTOR, LViewData, QUERIES, RENDERER, TVIEW, TView} from './interfaces/view';
|
||||||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||||
import {addRemoveViewFromContainer, appendChild, detachView, getChildLNode, getParentLNode, insertView, removeView} from './node_manipulation';
|
import {addRemoveViewFromContainer, appendChild, detachView, getChildLNode, getParentLNode, insertView, removeView} from './node_manipulation';
|
||||||
import {ViewRef} from './view_ref';
|
import {ViewRef} from './view_ref';
|
||||||
|
|
|
@ -76,6 +76,8 @@ export {
|
||||||
text as T,
|
text as T,
|
||||||
textBinding as t,
|
textBinding as t,
|
||||||
|
|
||||||
|
reference as r,
|
||||||
|
|
||||||
reserveSlots as rS,
|
reserveSlots as rS,
|
||||||
|
|
||||||
embeddedViewStart as V,
|
embeddedViewStart as V,
|
||||||
|
|
|
@ -16,13 +16,13 @@ import {assertDefined, assertEqual, assertLessThan, assertNotDefined, assertNotE
|
||||||
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
|
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
|
||||||
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
|
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
|
||||||
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
|
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
|
||||||
import {ComponentDefInternal, ComponentQuery, ComponentTemplate, DirectiveDefInternal, DirectiveDefListOrFactory, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
import {ComponentDefInternal, ComponentQuery, ComponentTemplate, DirectiveDefInternal, DirectiveDefListOrFactory, EmbeddedTemplate, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
||||||
import {LInjector} from './interfaces/injector';
|
import {LInjector} from './interfaces/injector';
|
||||||
import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node';
|
import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node';
|
||||||
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
||||||
import {LQueries} from './interfaces/query';
|
import {LQueries} from './interfaces/query';
|
||||||
import {ProceduralRenderer3, RComment, RElement, RText, Renderer3, RendererFactory3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
|
import {ProceduralRenderer3, RComment, RElement, RText, Renderer3, RendererFactory3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
|
||||||
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, CurrentMatchesList, DECLARATION_PARENT, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RootContext, SANITIZER, TAIL, TData, TVIEW, TView} from './interfaces/view';
|
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, CurrentMatchesList, DECLARATION_VIEW, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RootContext, SANITIZER, TAIL, TData, TVIEW, TView} from './interfaces/view';
|
||||||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||||
import {appendChild, appendProjectedNode, canInsertNativeNode, createTextNode, findComponentHost, getChildLNode, getLViewChild, getNextLNode, getParentLNode, insertView, removeView} from './node_manipulation';
|
import {appendChild, appendProjectedNode, canInsertNativeNode, createTextNode, findComponentHost, getChildLNode, getLViewChild, getNextLNode, getParentLNode, insertView, removeView} from './node_manipulation';
|
||||||
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
||||||
|
@ -334,7 +334,7 @@ export function createLViewData<T>(
|
||||||
null, // tail
|
null, // tail
|
||||||
-1, // containerIndex
|
-1, // containerIndex
|
||||||
null, // contentQueries
|
null, // contentQueries
|
||||||
null // declarationParent
|
null // declarationView
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,7 +500,7 @@ export function renderTemplate<T>(
|
||||||
* Such lViewNode will then be renderer with renderEmbeddedTemplate() (see below).
|
* Such lViewNode will then be renderer with renderEmbeddedTemplate() (see below).
|
||||||
*/
|
*/
|
||||||
export function createEmbeddedViewNode<T>(
|
export function createEmbeddedViewNode<T>(
|
||||||
tView: TView, context: T, declarationParent: LViewData, renderer: Renderer3,
|
tView: TView, context: T, declarationView: LViewData, renderer: Renderer3,
|
||||||
queries?: LQueries | null): LViewNode {
|
queries?: LQueries | null): LViewNode {
|
||||||
const _isParent = isParent;
|
const _isParent = isParent;
|
||||||
const _previousOrParentNode = previousOrParentNode;
|
const _previousOrParentNode = previousOrParentNode;
|
||||||
|
@ -509,7 +509,7 @@ export function createEmbeddedViewNode<T>(
|
||||||
|
|
||||||
const lView =
|
const lView =
|
||||||
createLViewData(renderer, tView, context, LViewFlags.CheckAlways, getCurrentSanitizer());
|
createLViewData(renderer, tView, context, LViewFlags.CheckAlways, getCurrentSanitizer());
|
||||||
lView[DECLARATION_PARENT] = declarationParent;
|
lView[DECLARATION_VIEW] = declarationView;
|
||||||
|
|
||||||
if (queries) {
|
if (queries) {
|
||||||
lView[QUERIES] = queries.createView();
|
lView[QUERIES] = queries.createView();
|
||||||
|
@ -547,7 +547,7 @@ export function renderEmbeddedTemplate<T>(
|
||||||
|
|
||||||
oldView = enterView(viewNode.data !, viewNode);
|
oldView = enterView(viewNode.data !, viewNode);
|
||||||
namespaceHTML();
|
namespaceHTML();
|
||||||
callTemplateWithContexts(rf, context, tView.template !, viewNode.data ![DECLARATION_PARENT] !);
|
callTemplateWithContexts(rf, context, tView.template !, viewNode.data ![DECLARATION_VIEW] !);
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
refreshDescendantViews();
|
refreshDescendantViews();
|
||||||
} else {
|
} else {
|
||||||
|
@ -577,11 +577,14 @@ export function renderEmbeddedTemplate<T>(
|
||||||
* <li *ngFor="let item of list"> {{ item }} </li>
|
* <li *ngFor="let item of list"> {{ item }} </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* function AppComponentTemplate(rf, ctx) {
|
* function ulTemplate(rf, ulCtx, appCtx) {...}
|
||||||
* // instructions
|
* function liTemplate(rf, liCtx, ulCtx, appCtx) {...}
|
||||||
* function ulTemplate(rf, ulCtx, appCtx) {...}
|
*
|
||||||
* function liTemplate(rf, liCtx, ulCtx, appCtx) {...}
|
* class AppComponent {...}
|
||||||
* }
|
* AppComponent.ngComponentDef = defineComponent({
|
||||||
|
* template: function AppComponentTemplate(rf, ctx) {...}
|
||||||
|
* });
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* The ul view's template must be called with its own context and its declaration
|
* The ul view's template must be called with its own context and its declaration
|
||||||
* parent, AppComponent. The li view's template must be called with its own context, its
|
* parent, AppComponent. The li view's template must be called with its own context, its
|
||||||
|
@ -591,71 +594,85 @@ export function renderEmbeddedTemplate<T>(
|
||||||
* can be declared in different views than they are used.
|
* can be declared in different views than they are used.
|
||||||
*
|
*
|
||||||
* @param rf The RenderFlags for this template invocation
|
* @param rf The RenderFlags for this template invocation
|
||||||
* @param context The context for this template
|
* @param currentContext The context for this template
|
||||||
* @param template The template function to call
|
* @param template The template function to call
|
||||||
* @param parent1 The declaration parent of the dynamic view
|
* @param parentView The declaration view of the dynamic view
|
||||||
*/
|
*/
|
||||||
function callTemplateWithContexts(
|
function callTemplateWithContexts<T>(
|
||||||
rf: RenderFlags, context: any, template: ComponentTemplate<any>, parent1: LViewData): void {
|
rf: RenderFlags, currentContext: T, template: EmbeddedTemplate<T>,
|
||||||
const parent2 = parent1[DECLARATION_PARENT];
|
parentView: LViewData): void {
|
||||||
|
const parentContext = parentView[CONTEXT];
|
||||||
|
const parentView2 = parentView[DECLARATION_VIEW];
|
||||||
|
|
||||||
// Calling a function with extra arguments has a VM cost, so only call with necessary args
|
// Calling a function with extra arguments has a VM cost, so only call with necessary args
|
||||||
if (!parent2) return template(rf, context, parent1[CONTEXT]);
|
if (parentView2 === null) {
|
||||||
|
return template(rf, currentContext, parentContext);
|
||||||
const parent3 = parent2[DECLARATION_PARENT];
|
|
||||||
if (!parent3) return template(rf, context, parent1[CONTEXT], parent2[CONTEXT]);
|
|
||||||
|
|
||||||
const parent4 = parent3[DECLARATION_PARENT];
|
|
||||||
if (!parent4) {
|
|
||||||
return template(rf, context, parent1[CONTEXT], parent2[CONTEXT], parent3[CONTEXT]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const parent5 = parent4[DECLARATION_PARENT];
|
const parentContext2 = parentView2[CONTEXT];
|
||||||
if (!parent5) {
|
const parentView3 = parentView2[DECLARATION_VIEW];
|
||||||
return template(
|
if (parentView3 === null) {
|
||||||
rf, context, parent1[CONTEXT], parent2[CONTEXT], parent3[CONTEXT], parent4[CONTEXT]);
|
return template(rf, currentContext, parentContext, parentContext2);
|
||||||
}
|
}
|
||||||
|
|
||||||
const parent6 = parent5[DECLARATION_PARENT];
|
const parentContext3 = parentView3[CONTEXT];
|
||||||
if (!parent6) {
|
const parentView4 = parentView3[DECLARATION_VIEW];
|
||||||
return template(
|
if (parentView4 === null) {
|
||||||
rf, context, parent1[CONTEXT], parent2[CONTEXT], parent3[CONTEXT], parent4[CONTEXT],
|
return template(rf, currentContext, parentContext, parentContext2, parentContext3);
|
||||||
parent5[CONTEXT]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const parent7 = parent6[DECLARATION_PARENT];
|
const parentContext4 = parentView4[CONTEXT];
|
||||||
if (!parent7) {
|
const parentView5 = parentView4[DECLARATION_VIEW];
|
||||||
|
if (parentView5 === null) {
|
||||||
return template(
|
return template(
|
||||||
rf, context, parent1[CONTEXT], parent2[CONTEXT], parent3[CONTEXT], parent4[CONTEXT],
|
rf, currentContext, parentContext, parentContext2, parentContext3, parentContext4);
|
||||||
parent5[CONTEXT], parent6[CONTEXT]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const parent8 = parent7[DECLARATION_PARENT];
|
const parentContext5 = parentView5[CONTEXT];
|
||||||
if (!parent8) {
|
const parentView6 = parentView5[DECLARATION_VIEW];
|
||||||
|
if (parentView6 === null) {
|
||||||
return template(
|
return template(
|
||||||
rf, context, parent1[CONTEXT], parent2[CONTEXT], parent3[CONTEXT], parent4[CONTEXT],
|
rf, currentContext, parentContext, parentContext2, parentContext3, parentContext4,
|
||||||
parent5[CONTEXT], parent6[CONTEXT], parent7[CONTEXT]);
|
parentContext5);
|
||||||
}
|
}
|
||||||
|
|
||||||
const parent9 = parent8[DECLARATION_PARENT];
|
const parentContext6 = parentView6[CONTEXT];
|
||||||
if (!parent9) {
|
const parentView7 = parentView6[DECLARATION_VIEW];
|
||||||
|
if (parentView7 === null) {
|
||||||
return template(
|
return template(
|
||||||
rf, context, parent1[CONTEXT], parent2[CONTEXT], parent3[CONTEXT], parent4[CONTEXT],
|
rf, currentContext, parentContext, parentContext2, parentContext3, parentContext4,
|
||||||
parent5[CONTEXT], parent6[CONTEXT], parent7[CONTEXT], parent8[CONTEXT]);
|
parentContext5, parentContext6);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentContext7 = parentView7[CONTEXT];
|
||||||
|
const parentView8 = parentView7[DECLARATION_VIEW];
|
||||||
|
if (parentView8 === null) {
|
||||||
|
return template(
|
||||||
|
rf, currentContext, parentContext, parentContext2, parentContext3, parentContext4,
|
||||||
|
parentContext5, parentContext6, parentContext7);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentContext8 = parentView8[CONTEXT];
|
||||||
|
const parentView9 = parentView8[DECLARATION_VIEW];
|
||||||
|
if (parentView9 === null) {
|
||||||
|
return template(
|
||||||
|
rf, currentContext, parentContext, parentContext2, parentContext3, parentContext4,
|
||||||
|
parentContext5, parentContext6, parentContext7, parentContext8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We support up to 8 nesting levels in embedded views before we give up and call apply()
|
// We support up to 8 nesting levels in embedded views before we give up and call apply()
|
||||||
const contexts = [
|
const templateArgs = [
|
||||||
parent1[CONTEXT], parent2[CONTEXT], parent3[CONTEXT], parent4[CONTEXT], parent5[CONTEXT],
|
rf, currentContext, parentContext, parentContext2, parentContext3, parentContext4,
|
||||||
parent6[CONTEXT], parent7[CONTEXT], parent8[CONTEXT], parent9[CONTEXT]
|
parentContext5, parentContext6, parentContext7, parentContext8, parentView9[CONTEXT]
|
||||||
];
|
];
|
||||||
|
|
||||||
let currentView: LViewData = parent9;
|
let currentDeclarationView: LViewData|null = parentView9[DECLARATION_VIEW];
|
||||||
while (currentView[DECLARATION_PARENT]) {
|
while (currentDeclarationView) {
|
||||||
contexts.push(currentView[DECLARATION_PARENT] ![CONTEXT]);
|
templateArgs.push(currentDeclarationView[CONTEXT]);
|
||||||
currentView = currentView[DECLARATION_PARENT] !;
|
currentDeclarationView = currentDeclarationView[DECLARATION_VIEW] !;
|
||||||
}
|
}
|
||||||
|
|
||||||
tView.template !(rf, context, ...contexts);
|
template.apply(null, templateArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderComponentOrTemplate<T>(
|
export function renderComponentOrTemplate<T>(
|
||||||
|
@ -990,7 +1007,7 @@ function getOrCreateTView(
|
||||||
* @param pipes Registry of pipes for this view
|
* @param pipes Registry of pipes for this view
|
||||||
*/
|
*/
|
||||||
export function createTView(
|
export function createTView(
|
||||||
viewIndex: number, template: ComponentTemplate<any>| null,
|
viewIndex: number, template: ComponentTemplate<any>| EmbeddedTemplate<any>| null,
|
||||||
directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null,
|
directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null,
|
||||||
viewQuery: ComponentQuery<any>| null): TView {
|
viewQuery: ComponentQuery<any>| null): TView {
|
||||||
ngDevMode && ngDevMode.tView++;
|
ngDevMode && ngDevMode.tView++;
|
||||||
|
@ -1811,7 +1828,7 @@ export function createLContainer(
|
||||||
* @param localRefs A set of local reference bindings on the element.
|
* @param localRefs A set of local reference bindings on the element.
|
||||||
*/
|
*/
|
||||||
export function container(
|
export function container(
|
||||||
index: number, template?: ComponentTemplate<any>, tagName?: string | null, attrs?: TAttributes,
|
index: number, template?: EmbeddedTemplate<any>, tagName?: string | null, attrs?: TAttributes,
|
||||||
localRefs?: string[] | null): void {
|
localRefs?: string[] | null): void {
|
||||||
ngDevMode &&
|
ngDevMode &&
|
||||||
assertEqual(
|
assertEqual(
|
||||||
|
@ -2636,6 +2653,20 @@ export function store<T>(index: number, value: T): void {
|
||||||
viewData[adjustedIndex] = value;
|
viewData[adjustedIndex] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Retrieves a value from an LViewData at the given nesting level. */
|
||||||
|
export function reference<T>(nestingLevel: number, index: number) {
|
||||||
|
let currentView = viewData;
|
||||||
|
while (nestingLevel > 0) {
|
||||||
|
ngDevMode && assertDefined(
|
||||||
|
currentView[DECLARATION_VIEW],
|
||||||
|
'Declaration view should be defined if nesting level is greater than 0.');
|
||||||
|
currentView = currentView[DECLARATION_VIEW] !;
|
||||||
|
nestingLevel--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadInternal<T>(index, currentView);
|
||||||
|
}
|
||||||
|
|
||||||
/** Retrieves a value from the `directives` array. */
|
/** Retrieves a value from the `directives` array. */
|
||||||
export function loadDirective<T>(index: number): T {
|
export function loadDirective<T>(index: number): T {
|
||||||
ngDevMode && assertDefined(directives, 'Directives array should be defined if reading a dir.');
|
ngDevMode && assertDefined(directives, 'Directives array should be defined if reading a dir.');
|
||||||
|
|
|
@ -11,11 +11,19 @@ import {RendererType2} from '../../render/api';
|
||||||
import {Type} from '../../type';
|
import {Type} from '../../type';
|
||||||
import {CssSelectorList} from './projection';
|
import {CssSelectorList} from './projection';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Definition of what a template rendering function should look like.
|
* Definition of what a template rendering function should look like for a component.
|
||||||
*/
|
*/
|
||||||
export type ComponentTemplate<T> = {
|
export type ComponentTemplate<T> = {
|
||||||
(rf: RenderFlags, ctx: T, ...parentCtx: ({} | null)[]): void; ngPrivateData?: never;
|
(rf: RenderFlags, ctx: T): void; ngPrivateData?: never;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definition of what a template rendering function should look like for an embedded view.
|
||||||
|
*/
|
||||||
|
export type EmbeddedTemplate<T> = {
|
||||||
|
(rf: RenderFlags, ctx: T, ...parentCtx: any[]): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -38,7 +38,7 @@ export const SANITIZER = 12;
|
||||||
export const TAIL = 13;
|
export const TAIL = 13;
|
||||||
export const CONTAINER_INDEX = 14;
|
export const CONTAINER_INDEX = 14;
|
||||||
export const CONTENT_QUERIES = 15;
|
export const CONTENT_QUERIES = 15;
|
||||||
export const DECLARATION_PARENT = 16;
|
export const DECLARATION_VIEW = 16;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `LViewData` stores all of the information needed to process the instructions as
|
* `LViewData` stores all of the information needed to process the instructions as
|
||||||
|
@ -63,7 +63,7 @@ export interface LViewData extends Array<any> {
|
||||||
* `LViewData`. Without this, the render method would have to keep a stack of
|
* `LViewData`. Without this, the render method would have to keep a stack of
|
||||||
* views as it is recursively rendering templates.
|
* views as it is recursively rendering templates.
|
||||||
*
|
*
|
||||||
* This is also the "insertion" parent for embedded views. This allows us to properly
|
* This is the "insertion" view for embedded views. This allows us to properly
|
||||||
* destroy embedded views.
|
* destroy embedded views.
|
||||||
*/
|
*/
|
||||||
[PARENT]: LViewData|null;
|
[PARENT]: LViewData|null;
|
||||||
|
@ -167,16 +167,16 @@ export interface LViewData extends Array<any> {
|
||||||
[CONTENT_QUERIES]: QueryList<any>[]|null;
|
[CONTENT_QUERIES]: QueryList<any>[]|null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parent view where this view's template was declared.
|
* View where this view's template was declared.
|
||||||
*
|
*
|
||||||
* Only applicable for dynamically created views. Will be null for inline/component views.
|
* Only applicable for dynamically created views. Will be null for inline/component views.
|
||||||
*
|
*
|
||||||
* The template for a dynamically created view may be declared in a different view than
|
* The template for a dynamically created view may be declared in a different view than
|
||||||
* it is inserted. We already track the "insertion parent" (view where the template was
|
* it is inserted. We already track the "insertion view" (view where the template was
|
||||||
* inserted) in LViewData[PARENT], but we also need access to the "declaration parent"
|
* inserted) in LViewData[PARENT], but we also need access to the "declaration view"
|
||||||
* (view where the template was declared). Otherwise, we wouldn't be able to call the
|
* (view where the template was declared). Otherwise, we wouldn't be able to call the
|
||||||
* view's template function with the proper contexts. Context should be inherited from
|
* view's template function with the proper contexts. Context should be inherited from
|
||||||
* the declaration parent tree, not the insertion parent tree.
|
* the declaration view tree, not the insertion view tree.
|
||||||
*
|
*
|
||||||
* Example (AppComponent template):
|
* Example (AppComponent template):
|
||||||
*
|
*
|
||||||
|
@ -184,13 +184,13 @@ export interface LViewData extends Array<any> {
|
||||||
* <some-comp [tpl]="foo"></some-comp> <-- inserted inside this component -->
|
* <some-comp [tpl]="foo"></some-comp> <-- inserted inside this component -->
|
||||||
*
|
*
|
||||||
* The <ng-template> above is declared in the AppComponent template, but it will be passed into
|
* The <ng-template> above is declared in the AppComponent template, but it will be passed into
|
||||||
* SomeComp and inserted there. In this case, the declaration parent would be the AppComponent,
|
* SomeComp and inserted there. In this case, the declaration view would be the AppComponent,
|
||||||
* but the insertion parent would be SomeComp. When we are removing views, we would want to
|
* but the insertion view would be SomeComp. When we are removing views, we would want to
|
||||||
* traverse through the insertion parent to clean up listeners. When we are calling the
|
* traverse through the insertion view to clean up listeners. When we are calling the
|
||||||
* template function during change detection, we need the declaration parent to get inherited
|
* template function during change detection, we need the declaration view to get inherited
|
||||||
* context.
|
* context.
|
||||||
*/
|
*/
|
||||||
[DECLARATION_PARENT]: LViewData|null;
|
[DECLARATION_VIEW]: LViewData|null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Flags associated with an LView (saved in LViewData[FLAGS]) */
|
/** Flags associated with an LView (saved in LViewData[FLAGS]) */
|
||||||
|
|
|
@ -81,6 +81,7 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
||||||
'ɵqR': r3.qR,
|
'ɵqR': r3.qR,
|
||||||
'ɵQr': r3.Qr,
|
'ɵQr': r3.Qr,
|
||||||
'ɵrS': r3.rS,
|
'ɵrS': r3.rS,
|
||||||
|
'ɵr': r3.r,
|
||||||
'ɵs': r3.s,
|
'ɵs': r3.s,
|
||||||
'ɵsm': r3.sm,
|
'ɵsm': r3.sm,
|
||||||
'ɵsp': r3.sp,
|
'ɵsp': r3.sp,
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_co
|
||||||
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEngine_InternalViewRef} from '../linker/view_ref';
|
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEngine_InternalViewRef} from '../linker/view_ref';
|
||||||
|
|
||||||
import {checkNoChanges, detectChanges, markViewDirty, storeCleanupFn, viewAttached} from './instructions';
|
import {checkNoChanges, detectChanges, markViewDirty, storeCleanupFn, viewAttached} from './instructions';
|
||||||
|
import {EmbeddedTemplate} from './interfaces/definition';
|
||||||
import {LViewNode} from './interfaces/node';
|
import {LViewNode} from './interfaces/node';
|
||||||
import {FLAGS, LViewData, LViewFlags} from './interfaces/view';
|
import {FLAGS, LViewData, LViewFlags} from './interfaces/view';
|
||||||
import {destroyLView} from './node_manipulation';
|
import {destroyLView} from './node_manipulation';
|
||||||
|
@ -243,3 +244,30 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int
|
||||||
|
|
||||||
attachToAppRef(appRef: ApplicationRef) { this._appRef = appRef; }
|
attachToAppRef(appRef: ApplicationRef) { this._appRef = appRef; }
|
||||||
}
|
}
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
|
||||||
|
|
||||||
|
export class EmbeddedViewRef<T> extends ViewRef<T> {
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
_lViewNode: LViewNode;
|
||||||
|
private _viewContainerRef: viewEngine_ViewContainerRef|null = null;
|
||||||
|
|
||||||
|
constructor(viewNode: LViewNode, template: EmbeddedTemplate<T>, context: T) {
|
||||||
|
super(viewNode.data, context);
|
||||||
|
this._lViewNode = viewNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(): void {
|
||||||
|
if (this._viewContainerRef && viewAttached(this._view)) {
|
||||||
|
this._viewContainerRef.detach(this._viewContainerRef.indexOf(this));
|
||||||
|
this._viewContainerRef = null;
|
||||||
|
}
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
attachToViewContainerRef(vcRef: viewEngine_ViewContainerRef) { this._viewContainerRef = vcRef; }
|
||||||
|
}
|
||||||
|
>>>>>>> fixup! fix(ivy): flatten template fns for nested views
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
{
|
{
|
||||||
"name": "ChangeDetectionStrategy"
|
"name": "ChangeDetectionStrategy"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "DECLARATION_VIEW"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "DIRECTIVES"
|
"name": "DIRECTIVES"
|
||||||
},
|
},
|
||||||
|
@ -98,6 +101,9 @@
|
||||||
{
|
{
|
||||||
"name": "callHooks"
|
"name": "callHooks"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "callTemplateWithContexts"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "canInsertNativeNode"
|
"name": "canInsertNativeNode"
|
||||||
},
|
},
|
||||||
|
@ -210,10 +216,10 @@
|
||||||
"name": "refreshContentQueries"
|
"name": "refreshContentQueries"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "refreshDynamicEmbeddedViews"
|
"name": "refreshDescendantViews"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "refreshView"
|
"name": "refreshDynamicEmbeddedViews"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "renderComponent"
|
"name": "renderComponent"
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
{
|
{
|
||||||
"name": "ChangeDetectionStrategy"
|
"name": "ChangeDetectionStrategy"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "DECLARATION_VIEW"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "DIRECTIVES"
|
"name": "DIRECTIVES"
|
||||||
},
|
},
|
||||||
|
@ -137,6 +140,24 @@
|
||||||
{
|
{
|
||||||
"name": "TemplateRef$1"
|
"name": "TemplateRef$1"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "ToDoAppComponent_footer_Template_6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ToDoAppComponent_footer_button_Template_5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ToDoAppComponent_section_Template_5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ToDoAppComponent_section_input_Template_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ToDoAppComponent_section_li_Template_3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ToDoAppComponent_section_li_input_Template_6"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Todo"
|
"name": "Todo"
|
||||||
},
|
},
|
||||||
|
@ -305,6 +326,9 @@
|
||||||
{
|
{
|
||||||
"name": "callHooks"
|
"name": "callHooks"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "callTemplateWithContexts"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "canInsertNativeNode"
|
"name": "canInsertNativeNode"
|
||||||
},
|
},
|
||||||
|
@ -701,6 +725,9 @@
|
||||||
{
|
{
|
||||||
"name": "readElementValue"
|
"name": "readElementValue"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "reference"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "refreshChildComponents"
|
"name": "refreshChildComponents"
|
||||||
},
|
},
|
||||||
|
@ -708,10 +735,10 @@
|
||||||
"name": "refreshContentQueries"
|
"name": "refreshContentQueries"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "refreshDynamicEmbeddedViews"
|
"name": "refreshDescendantViews"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "refreshView"
|
"name": "refreshDynamicEmbeddedViews"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "removeListeners"
|
"name": "removeListeners"
|
||||||
|
|
|
@ -226,34 +226,35 @@ describe('@angular/common integration', () => {
|
||||||
elementProperty(1, 'ngForOf', bind(myApp.items));
|
elementProperty(1, 'ngForOf', bind(myApp.items));
|
||||||
}
|
}
|
||||||
|
|
||||||
function liTemplate(rf1: RenderFlags, row: any, myApp: MyApp) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'li');
|
|
||||||
{ container(1, spanTemplate, null, ['ngForOf', '']); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
const r1 = row.$implicit as any;
|
|
||||||
elementProperty(1, 'ngForOf', bind(r1.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function spanTemplate(rf1: RenderFlags, cell: any, row: any, myApp: MyApp) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'span');
|
|
||||||
{ text(1); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
textBinding(
|
|
||||||
1, interpolation2('', cell.$implicit, ' - ', (row.$implicit as any).value, ''));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
directives: () => [NgForOf]
|
directives: () => [NgForOf]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function liTemplate(rf1: RenderFlags, row: any, myApp: MyApp) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'li');
|
||||||
|
{ container(1, spanTemplate, null, ['ngForOf', '']); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
const r1 = row.$implicit as any;
|
||||||
|
elementProperty(1, 'ngForOf', bind(r1.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function spanTemplate(rf1: RenderFlags, cell: any, row: any, myApp: MyApp) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'span');
|
||||||
|
{ text(1); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
textBinding(
|
||||||
|
1, interpolation2('', cell.$implicit, ' - ', (row.$implicit as any).value, ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fixture = new ComponentFixture(MyApp);
|
const fixture = new ComponentFixture(MyApp);
|
||||||
|
|
||||||
// Change detection cycle, no model changes
|
// Change detection cycle, no model changes
|
||||||
|
@ -392,137 +393,136 @@ describe('@angular/common integration', () => {
|
||||||
elementProperty(0, 'ngForOf', bind(myApp.items));
|
elementProperty(0, 'ngForOf', bind(myApp.items));
|
||||||
}
|
}
|
||||||
|
|
||||||
function itemTemplate0(rf1: RenderFlags, item0: any, myApp: MyApp) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'span');
|
|
||||||
{ container(1, itemTemplate1, null, ['ngForOf', '']); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
const item = item0.$implicit as any;
|
|
||||||
elementProperty(1, 'ngForOf', bind(item.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function itemTemplate1(rf1: RenderFlags, item1: any, item0: any, myApp: MyApp) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'span');
|
|
||||||
{ container(1, itemTemplate2, null, ['ngForOf', '']); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
const item = item1.$implicit as any;
|
|
||||||
elementProperty(1, 'ngForOf', bind(item.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function itemTemplate2(
|
|
||||||
rf1: RenderFlags, item2: any, item1: any, item0: any, myApp: MyApp) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'span');
|
|
||||||
{ container(1, itemTemplate3, null, ['ngForOf', '']); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
const item = item2.$implicit as any;
|
|
||||||
elementProperty(1, 'ngForOf', bind(item.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function itemTemplate3(
|
|
||||||
rf1: RenderFlags, item3: any, item2: any, item1: any, item0: any, myApp: MyApp) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'span');
|
|
||||||
{ container(1, itemTemplate4, null, ['ngForOf', '']); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
const item = item3.$implicit as any;
|
|
||||||
elementProperty(1, 'ngForOf', bind(item.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function itemTemplate4(
|
|
||||||
rf1: RenderFlags, item4: any, item3: any, item2: any, item1: any, item0: any,
|
|
||||||
myApp: MyApp) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'span');
|
|
||||||
{ container(1, itemTemplate5, null, ['ngForOf', '']); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
const item = item4.$implicit as any;
|
|
||||||
elementProperty(1, 'ngForOf', bind(item.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function itemTemplate5(
|
|
||||||
rf1: RenderFlags, item5: any, item4: any, item3: any, item2: any, item1: any,
|
|
||||||
item0: any, myApp: MyApp) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'span');
|
|
||||||
{ container(1, itemTemplate6, null, ['ngForOf', '']); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
const item = item5.$implicit as any;
|
|
||||||
elementProperty(1, 'ngForOf', bind(item.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function itemTemplate6(
|
|
||||||
rf1: RenderFlags, item6: any, item5: any, item4: any, item3: any, item2: any,
|
|
||||||
item1: any, item0: any, myApp: MyApp) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'span');
|
|
||||||
{ container(1, itemTemplate7, null, ['ngForOf', '']); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
const item = item6.$implicit as any;
|
|
||||||
elementProperty(1, 'ngForOf', bind(item.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function itemTemplate7(
|
|
||||||
rf1: RenderFlags, item7: any, item6: any, item5: any, item4: any, item3: any,
|
|
||||||
item2: any, item1: any, item0: any, myApp: MyApp) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'span');
|
|
||||||
{ container(1, itemTemplate8, null, ['ngForOf', '']); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
const item = item7.$implicit as any;
|
|
||||||
elementProperty(1, 'ngForOf', bind(item.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function itemTemplate8(
|
|
||||||
rf1: RenderFlags, item8: any, item7: any, item6: any, item5: any, item4: any,
|
|
||||||
item3: any, item2: any, item1: any, item0: any, myApp: MyApp) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'span');
|
|
||||||
{ text(1); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
textBinding(1, interpolationV([
|
|
||||||
'', item8.$implicit, '.', item7.$implicit.value,
|
|
||||||
'.', item6.$implicit.value, '.', item5.$implicit.value,
|
|
||||||
'.', item4.$implicit.value, '.', item3.$implicit.value,
|
|
||||||
'.', item2.$implicit.value, '.', item1.$implicit.value,
|
|
||||||
'.', item0.$implicit.value, '.', myApp.value,
|
|
||||||
''
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
directives: () => [NgForOf]
|
directives: () => [NgForOf]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function itemTemplate0(rf1: RenderFlags, item0: any, myApp: MyApp) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'span');
|
||||||
|
{ container(1, itemTemplate1, null, ['ngForOf', '']); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
const item = item0.$implicit as any;
|
||||||
|
elementProperty(1, 'ngForOf', bind(item.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function itemTemplate1(rf1: RenderFlags, item1: any, item0: any, myApp: MyApp) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'span');
|
||||||
|
{ container(1, itemTemplate2, null, ['ngForOf', '']); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
const item = item1.$implicit as any;
|
||||||
|
elementProperty(1, 'ngForOf', bind(item.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function itemTemplate2(rf1: RenderFlags, item2: any, item1: any, item0: any, myApp: MyApp) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'span');
|
||||||
|
{ container(1, itemTemplate3, null, ['ngForOf', '']); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
const item = item2.$implicit as any;
|
||||||
|
elementProperty(1, 'ngForOf', bind(item.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function itemTemplate3(
|
||||||
|
rf1: RenderFlags, item3: any, item2: any, item1: any, item0: any, myApp: MyApp) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'span');
|
||||||
|
{ container(1, itemTemplate4, null, ['ngForOf', '']); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
const item = item3.$implicit as any;
|
||||||
|
elementProperty(1, 'ngForOf', bind(item.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function itemTemplate4(
|
||||||
|
rf1: RenderFlags, item4: any, item3: any, item2: any, item1: any, item0: any,
|
||||||
|
myApp: MyApp) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'span');
|
||||||
|
{ container(1, itemTemplate5, null, ['ngForOf', '']); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
const item = item4.$implicit as any;
|
||||||
|
elementProperty(1, 'ngForOf', bind(item.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function itemTemplate5(
|
||||||
|
rf1: RenderFlags, item5: any, item4: any, item3: any, item2: any, item1: any, item0: any,
|
||||||
|
myApp: MyApp) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'span');
|
||||||
|
{ container(1, itemTemplate6, null, ['ngForOf', '']); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
const item = item5.$implicit as any;
|
||||||
|
elementProperty(1, 'ngForOf', bind(item.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function itemTemplate6(
|
||||||
|
rf1: RenderFlags, item6: any, item5: any, item4: any, item3: any, item2: any, item1: any,
|
||||||
|
item0: any, myApp: MyApp) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'span');
|
||||||
|
{ container(1, itemTemplate7, null, ['ngForOf', '']); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
const item = item6.$implicit as any;
|
||||||
|
elementProperty(1, 'ngForOf', bind(item.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function itemTemplate7(
|
||||||
|
rf1: RenderFlags, item7: any, item6: any, item5: any, item4: any, item3: any, item2: any,
|
||||||
|
item1: any, item0: any, myApp: MyApp) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'span');
|
||||||
|
{ container(1, itemTemplate8, null, ['ngForOf', '']); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
const item = item7.$implicit as any;
|
||||||
|
elementProperty(1, 'ngForOf', bind(item.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function itemTemplate8(
|
||||||
|
rf1: RenderFlags, item8: any, item7: any, item6: any, item5: any, item4: any, item3: any,
|
||||||
|
item2: any, item1: any, item0: any, myApp: MyApp) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'span');
|
||||||
|
{ text(1); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
textBinding(
|
||||||
|
1, interpolationV([
|
||||||
|
'', item8.$implicit, '.', item7.$implicit.value, '.', item6.$implicit.value,
|
||||||
|
'.', item5.$implicit.value, '.', item4.$implicit.value, '.', item3.$implicit.value,
|
||||||
|
'.', item2.$implicit.value, '.', item1.$implicit.value, '.', item0.$implicit.value,
|
||||||
|
'.', myApp.value, ''
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fixture = new ComponentFixture(MyApp);
|
const fixture = new ComponentFixture(MyApp);
|
||||||
|
|
||||||
expect(fixture.html)
|
expect(fixture.html)
|
||||||
|
@ -564,31 +564,33 @@ describe('@angular/common integration', () => {
|
||||||
elementProperty(1, 'ngIf', bind(myApp.showing));
|
elementProperty(1, 'ngIf', bind(myApp.showing));
|
||||||
}
|
}
|
||||||
|
|
||||||
function templateOne(rf: RenderFlags, ctx: any, parent: MyApp) {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'div');
|
|
||||||
{ text(1); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
textBinding(1, bind(myApp.valueOne));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function templateTwo(rf: RenderFlags, ctx: any, parent: MyApp) {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'div');
|
|
||||||
{ text(1); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
textBinding(1, bind(myApp.valueTwo));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
directives: () => [NgIf]
|
directives: () => [NgIf]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function templateOne(rf: RenderFlags, ctx: any, myApp: MyApp) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'div');
|
||||||
|
{ text(1); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf & RenderFlags.Update) {
|
||||||
|
textBinding(1, bind(myApp.valueOne));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function templateTwo(rf: RenderFlags, ctx: any, myApp: MyApp) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'div');
|
||||||
|
{ text(1); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf & RenderFlags.Update) {
|
||||||
|
textBinding(1, bind(myApp.valueTwo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fixture = new ComponentFixture(MyApp);
|
const fixture = new ComponentFixture(MyApp);
|
||||||
expect(fixture.html).toEqual('<div>one</div><div>two</div>');
|
expect(fixture.html).toEqual('<div>one</div><div>two</div>');
|
||||||
|
|
||||||
|
|
|
@ -389,28 +389,31 @@ describe('recursive components', () => {
|
||||||
elementProperty(2, 'ngIf', bind(ctx.data.right));
|
elementProperty(2, 'ngIf', bind(ctx.data.right));
|
||||||
}
|
}
|
||||||
|
|
||||||
function IfTemplate(rf1: RenderFlags, left: any, parent: NgIfTree) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'ng-if-tree');
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
elementProperty(0, 'data', bind(parent.data.left));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function IfTemplate2(rf1: RenderFlags, right: any, parent: NgIfTree) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'ng-if-tree');
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
elementProperty(0, 'data', bind(parent.data.right));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
inputs: {data: 'data'},
|
inputs: {data: 'data'},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function IfTemplate(rf1: RenderFlags, left: any, parent: NgIfTree) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'ng-if-tree');
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
elementProperty(0, 'data', bind(parent.data.left));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function IfTemplate2(rf1: RenderFlags, right: any, parent: NgIfTree) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'ng-if-tree');
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
elementProperty(0, 'data', bind(parent.data.right));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(NgIfTree.ngComponentDef as ComponentDefInternal<NgIfTree>).directiveDefs =
|
(NgIfTree.ngComponentDef as ComponentDefInternal<NgIfTree>).directiveDefs =
|
||||||
() => [NgIfTree.ngComponentDef, NgIf.ngDirectiveDef];
|
() => [NgIfTree.ngComponentDef, NgIf.ngDirectiveDef];
|
||||||
|
|
||||||
|
|
|
@ -823,14 +823,15 @@ describe('content projection', () => {
|
||||||
elementProperty(1, 'ngIf', bind(ctx.showing));
|
elementProperty(1, 'ngIf', bind(ctx.showing));
|
||||||
}
|
}
|
||||||
|
|
||||||
function IfTemplate(rf1: RenderFlags, ctx1: any, child: any) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
projectionDef();
|
|
||||||
projection(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [NgIf]);
|
}, [NgIf]);
|
||||||
|
|
||||||
|
function IfTemplate(rf1: RenderFlags, ctx: any, child: any) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
projectionDef();
|
||||||
|
projection(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let child: {showing: boolean};
|
let child: {showing: boolean};
|
||||||
/**
|
/**
|
||||||
* <child>
|
* <child>
|
||||||
|
@ -887,14 +888,15 @@ describe('content projection', () => {
|
||||||
elementProperty(1, 'ngIf', bind(ctx.showing));
|
elementProperty(1, 'ngIf', bind(ctx.showing));
|
||||||
}
|
}
|
||||||
|
|
||||||
function IfTemplate(rf1: RenderFlags, ctx1: any, child: any) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
projectionDef();
|
|
||||||
projection(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [NgIf]);
|
}, [NgIf]);
|
||||||
|
|
||||||
|
function IfTemplate(rf: RenderFlags, ctx: any, child: any) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
projectionDef();
|
||||||
|
projection(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let child: {showing: boolean};
|
let child: {showing: boolean};
|
||||||
/**
|
/**
|
||||||
* <child>
|
* <child>
|
||||||
|
|
|
@ -6,10 +6,11 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {defineComponent, defineDirective} from '../../src/render3/index';
|
import {AttributeMarker, defineComponent, defineDirective} from '../../src/render3/index';
|
||||||
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementAttribute, elementClassProp, elementEnd, elementProperty, elementStart, elementStyling, elementStylingApply, embeddedViewEnd, embeddedViewStart, load, text, textBinding} from '../../src/render3/instructions';
|
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementAttribute, elementClassProp, elementEnd, elementProperty, elementStart, elementStyling, elementStylingApply, embeddedViewEnd, embeddedViewStart, interpolation2, load, reference, text, textBinding} from '../../src/render3/instructions';
|
||||||
import {InitialStylingFlags, RenderFlags} from '../../src/render3/interfaces/definition';
|
import {InitialStylingFlags, RenderFlags} from '../../src/render3/interfaces/definition';
|
||||||
|
|
||||||
|
import {NgIf} from './common_with_def';
|
||||||
import {ComponentFixture, createComponent, renderToHtml} from './render_util';
|
import {ComponentFixture, createComponent, renderToHtml} from './render_util';
|
||||||
|
|
||||||
describe('exports', () => {
|
describe('exports', () => {
|
||||||
|
@ -21,9 +22,8 @@ describe('exports', () => {
|
||||||
element(0, 'input', ['value', 'one'], ['myInput', '']);
|
element(0, 'input', ['value', 'one'], ['myInput', '']);
|
||||||
text(2);
|
text(2);
|
||||||
}
|
}
|
||||||
let tmp: any;
|
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
tmp = load(1);
|
const tmp = load(1) as any;
|
||||||
textBinding(2, tmp.value);
|
textBinding(2, tmp.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,8 @@ describe('exports', () => {
|
||||||
element(0, 'comp', null, ['myComp', '']);
|
element(0, 'comp', null, ['myComp', '']);
|
||||||
text(2);
|
text(2);
|
||||||
}
|
}
|
||||||
let tmp: any;
|
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
tmp = load(1);
|
const tmp = load(1) as any;
|
||||||
textBinding(2, tmp.name);
|
textBinding(2, tmp.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,9 +93,8 @@ describe('exports', () => {
|
||||||
element(0, 'comp', null, ['myComp', '']);
|
element(0, 'comp', null, ['myComp', '']);
|
||||||
element(2, 'div', ['myDir', '']);
|
element(2, 'div', ['myDir', '']);
|
||||||
}
|
}
|
||||||
let tmp: any;
|
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
tmp = load(1);
|
const tmp = load(1) as any;
|
||||||
elementProperty(2, 'myDir', bind(tmp));
|
elementProperty(2, 'myDir', bind(tmp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,9 +111,8 @@ describe('exports', () => {
|
||||||
element(0, 'div', ['someDir', ''], ['myDir', 'someDir']);
|
element(0, 'div', ['someDir', ''], ['myDir', 'someDir']);
|
||||||
text(2);
|
text(2);
|
||||||
}
|
}
|
||||||
let tmp: any;
|
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
tmp = load(1);
|
const tmp = load(1) as any;
|
||||||
textBinding(2, tmp.name);
|
textBinding(2, tmp.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,8 +152,8 @@ describe('exports', () => {
|
||||||
text(0);
|
text(0);
|
||||||
element(1, 'input', ['value', 'one'], ['myInput', '']);
|
element(1, 'input', ['value', 'one'], ['myInput', '']);
|
||||||
}
|
}
|
||||||
const tmp = load(2) as any;
|
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
|
const tmp = load(2) as any;
|
||||||
textBinding(0, bind(tmp.value));
|
textBinding(0, bind(tmp.value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,8 +169,8 @@ describe('exports', () => {
|
||||||
element(0, 'div');
|
element(0, 'div');
|
||||||
element(1, 'input', ['value', 'one'], ['myInput', '']);
|
element(1, 'input', ['value', 'one'], ['myInput', '']);
|
||||||
}
|
}
|
||||||
const tmp = load(2) as any;
|
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
|
const tmp = load(2) as any;
|
||||||
elementProperty(0, 'title', bind(tmp.value));
|
elementProperty(0, 'title', bind(tmp.value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,8 +185,8 @@ describe('exports', () => {
|
||||||
element(0, 'div');
|
element(0, 'div');
|
||||||
element(1, 'input', ['value', 'one'], ['myInput', '']);
|
element(1, 'input', ['value', 'one'], ['myInput', '']);
|
||||||
}
|
}
|
||||||
const tmp = load(2) as any;
|
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
|
const tmp = load(2) as any;
|
||||||
elementAttribute(0, 'aria-label', bind(tmp.value));
|
elementAttribute(0, 'aria-label', bind(tmp.value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,8 +203,8 @@ describe('exports', () => {
|
||||||
elementEnd();
|
elementEnd();
|
||||||
element(1, 'input', ['type', 'checkbox', 'checked', 'true'], ['myInput', '']);
|
element(1, 'input', ['type', 'checkbox', 'checked', 'true'], ['myInput', '']);
|
||||||
}
|
}
|
||||||
const tmp = load(2) as any;
|
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
|
const tmp = load(2) as any;
|
||||||
elementClassProp(0, 0, tmp.checked);
|
elementClassProp(0, 0, tmp.checked);
|
||||||
elementStylingApply(0);
|
elementStylingApply(0);
|
||||||
}
|
}
|
||||||
|
@ -253,9 +250,8 @@ describe('exports', () => {
|
||||||
element(0, 'div', ['myDir', '']);
|
element(0, 'div', ['myDir', '']);
|
||||||
element(1, 'comp', null, ['myComp', '']);
|
element(1, 'comp', null, ['myComp', '']);
|
||||||
}
|
}
|
||||||
let tmp: any;
|
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
tmp = load(2) as any;
|
const tmp = load(2) as any;
|
||||||
elementProperty(0, 'myDir', bind(tmp));
|
elementProperty(0, 'myDir', bind(tmp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,11 +270,9 @@ describe('exports', () => {
|
||||||
element(2, 'comp', null, ['myComp', '']);
|
element(2, 'comp', null, ['myComp', '']);
|
||||||
element(4, 'input', ['value', 'one'], ['myInput', '']);
|
element(4, 'input', ['value', 'one'], ['myInput', '']);
|
||||||
}
|
}
|
||||||
let tmp1: any;
|
|
||||||
let tmp2: any;
|
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
tmp1 = load(3) as any;
|
const tmp1 = load(3) as any;
|
||||||
tmp2 = load(5) as any;
|
const tmp2 = load(5) as any;
|
||||||
textBinding(0, bind(tmp2.value));
|
textBinding(0, bind(tmp2.value));
|
||||||
textBinding(1, bind(tmp1.name));
|
textBinding(1, bind(tmp1.name));
|
||||||
}
|
}
|
||||||
|
@ -315,13 +309,12 @@ describe('exports', () => {
|
||||||
if (ctx.condition) {
|
if (ctx.condition) {
|
||||||
let rf1 = embeddedViewStart(1);
|
let rf1 = embeddedViewStart(1);
|
||||||
{
|
{
|
||||||
let tmp: any;
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
if (rf1 & RenderFlags.Create) {
|
||||||
text(0);
|
text(0);
|
||||||
element(1, 'input', ['value', 'one'], ['myInput', '']);
|
element(1, 'input', ['value', 'one'], ['myInput', '']);
|
||||||
}
|
}
|
||||||
if (rf1 & RenderFlags.Update) {
|
if (rf1 & RenderFlags.Update) {
|
||||||
tmp = load(2);
|
const tmp = load(2) as any;
|
||||||
textBinding(0, bind(tmp.value));
|
textBinding(0, bind(tmp.value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -337,5 +330,71 @@ describe('exports', () => {
|
||||||
})).toEqual('<div>one<input value="one"></div>');
|
})).toEqual('<div>one<input value="one"></div>');
|
||||||
expect(renderToHtml(Template, {condition: false})).toEqual('<div></div>');
|
expect(renderToHtml(Template, {condition: false})).toEqual('<div></div>');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support local refs in nested dynamic views', () => {
|
||||||
|
/**
|
||||||
|
* <input value="one" #outerInput>
|
||||||
|
* <div *ngIf="outer">
|
||||||
|
* {{ outerInput.value }}
|
||||||
|
*
|
||||||
|
* <input value = "two" #innerInput>
|
||||||
|
*
|
||||||
|
* <div *ngIf="inner">
|
||||||
|
* {{ outerInput.value }} - {{ innerInput.value}}
|
||||||
|
* </div>
|
||||||
|
* </div>
|
||||||
|
*/
|
||||||
|
const App = createComponent('app', function(rf: RenderFlags, app: any) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'input', ['value', 'one'], ['outerInput', '']);
|
||||||
|
elementEnd();
|
||||||
|
container(2, outerTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']);
|
||||||
|
}
|
||||||
|
if (rf & RenderFlags.Update) {
|
||||||
|
elementProperty(2, 'ngIf', bind(app.outer));
|
||||||
|
}
|
||||||
|
}, [NgIf]);
|
||||||
|
|
||||||
|
function outerTemplate(rf: RenderFlags, outer: any, app: any) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'div');
|
||||||
|
{
|
||||||
|
text(1);
|
||||||
|
elementStart(2, 'input', ['value', 'two'], ['innerInput', '']);
|
||||||
|
elementEnd();
|
||||||
|
container(4, innerTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']);
|
||||||
|
}
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
const outerInput = reference(1, 1) as any;
|
||||||
|
if (rf & RenderFlags.Update) {
|
||||||
|
textBinding(1, bind(outerInput.value));
|
||||||
|
elementProperty(4, 'ngIf', bind(app.inner));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function innerTemplate(rf: RenderFlags, inner: any, outer: any, app: any) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'div');
|
||||||
|
{ text(1); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
const outerInput = reference(2, 1) as any;
|
||||||
|
const innerInput = reference(1, 3) as any;
|
||||||
|
if (rf & RenderFlags.Update) {
|
||||||
|
textBinding(1, interpolation2('', outerInput.value, ' - ', innerInput.value, ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fixture = new ComponentFixture(App);
|
||||||
|
fixture.component.outer = true;
|
||||||
|
fixture.component.inner = true;
|
||||||
|
fixture.update();
|
||||||
|
expect(fixture.html)
|
||||||
|
.toEqual(`<input value="one"><div>one<input value="two"><div>one - two</div></div>`);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -506,9 +506,9 @@ describe('ViewContainerRef', () => {
|
||||||
*
|
*
|
||||||
* <child [tpl]="foo"></child> <-- template insertion inside
|
* <child [tpl]="foo"></child> <-- template insertion inside
|
||||||
*/
|
*/
|
||||||
const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
|
const Parent = createComponent('parent', function(rf: RenderFlags, parent: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
container(0, template);
|
container(0, fooTemplate);
|
||||||
elementStart(1, 'child');
|
elementStart(1, 'child');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
}
|
}
|
||||||
|
@ -519,19 +519,20 @@ describe('ViewContainerRef', () => {
|
||||||
elementProperty(1, 'tpl', bind(tplRef));
|
elementProperty(1, 'tpl', bind(tplRef));
|
||||||
}
|
}
|
||||||
|
|
||||||
function template(rf1: RenderFlags, ctx1: any, parent: any) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'div');
|
|
||||||
{ text(1); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
textBinding(1, bind(parent.name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [Child]);
|
}, [Child]);
|
||||||
|
|
||||||
|
function fooTemplate(rf1: RenderFlags, ctx: any, parent: any) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'div');
|
||||||
|
{ text(1); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
textBinding(1, bind(parent.name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fixture = new ComponentFixture(Parent);
|
const fixture = new ComponentFixture(Parent);
|
||||||
fixture.component.name = 'Parent';
|
fixture.component.name = 'Parent';
|
||||||
fixture.update();
|
fixture.update();
|
||||||
|
@ -609,37 +610,37 @@ describe('ViewContainerRef', () => {
|
||||||
elementProperty(1, 'rows', bind(parent.rows));
|
elementProperty(1, 'rows', bind(parent.rows));
|
||||||
}
|
}
|
||||||
|
|
||||||
function rowTemplate(rf1: RenderFlags, row: any, parent: any) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
container(0, cellTemplate);
|
|
||||||
elementStart(1, 'loop-comp');
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
// Hack until we have local refs for templates
|
|
||||||
const cellTemplateRef =
|
|
||||||
getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
|
|
||||||
elementProperty(1, 'tpl', bind(cellTemplateRef));
|
|
||||||
elementProperty(1, 'rows', bind(row.$implicit.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function cellTemplate(rf1: RenderFlags, cell: any, row: any, parent: any) {
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'div');
|
|
||||||
{ text(1); }
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
textBinding(
|
|
||||||
1, interpolation3(
|
|
||||||
'', cell.$implicit, ' - ', row.$implicit.value, ' - ', parent.name, ''));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [LoopComp]);
|
}, [LoopComp]);
|
||||||
|
|
||||||
|
function rowTemplate(rf1: RenderFlags, row: any, parent: any) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
container(0, cellTemplate);
|
||||||
|
elementStart(1, 'loop-comp');
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
// Hack until we have local refs for templates
|
||||||
|
const cellTemplateRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
|
||||||
|
elementProperty(1, 'tpl', bind(cellTemplateRef));
|
||||||
|
elementProperty(1, 'rows', bind(row.$implicit.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cellTemplate(rf1: RenderFlags, cell: any, row: any, parent: any) {
|
||||||
|
if (rf1 & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'div');
|
||||||
|
{ text(1); }
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rf1 & RenderFlags.Update) {
|
||||||
|
textBinding(
|
||||||
|
1, interpolation3(
|
||||||
|
'', cell.$implicit, ' - ', row.$implicit.value, ' - ', parent.name, ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fixture = new ComponentFixture(Parent);
|
const fixture = new ComponentFixture(Parent);
|
||||||
fixture.component.name = 'Parent';
|
fixture.component.name = 'Parent';
|
||||||
fixture.component.rows =
|
fixture.component.rows =
|
||||||
|
|
Loading…
Reference in New Issue