refactor(ivy): use generated consts value to set binding index (#25533)

PR Close #25533
This commit is contained in:
Kara Erickson 2018-08-16 18:53:21 -07:00 committed by Jason Aden
parent 4708cb91ef
commit f2aa9c6a7f
52 changed files with 2296 additions and 1767 deletions

View File

@ -19,6 +19,7 @@ export class LargeTableComponent {
static ngComponentDef: ComponentDefInternal<LargeTableComponent> = ɵdefineComponent({
type: LargeTableComponent,
selectors: [['largetable']],
consts: 3,
template: function(rf: ɵRenderFlags, ctx: LargeTableComponent) {
if (rf & ɵRenderFlags.Create) {
ɵelementStart(0, 'table');
@ -33,7 +34,7 @@ export class LargeTableComponent {
ɵcontainerRefreshStart(2);
{
for (let row of ctx.data) {
let rf1 = ɵembeddedViewStart(1);
let rf1 = ɵembeddedViewStart(1, 2);
{
if (rf1 & ɵRenderFlags.Create) {
ɵelementStart(0, 'tr');
@ -44,7 +45,7 @@ export class LargeTableComponent {
ɵcontainerRefreshStart(1);
{
for (let cell of row) {
let rf2 = ɵembeddedViewStart(2);
let rf2 = ɵembeddedViewStart(2, 2);
{
if (rf2 & ɵRenderFlags.Create) {
ɵelementStart(0, 'td');

View File

@ -38,6 +38,7 @@ export class TreeComponent {
static ngComponentDef = ɵdefineComponent({
type: TreeComponent,
selectors: [['tree']],
consts: 4,
template: function(rf: ɵRenderFlags, ctx: TreeComponent) {
if (rf & ɵRenderFlags.Create) {
ɵelementStart(0, 'span');
@ -53,7 +54,7 @@ export class TreeComponent {
ɵcontainerRefreshStart(2);
{
if (ctx.data.left != null) {
let rf0 = ɵembeddedViewStart(0);
let rf0 = ɵembeddedViewStart(0, 1);
{
if (rf0 & ɵRenderFlags.Create) {
ɵelementStart(0, 'tree');
@ -70,7 +71,7 @@ export class TreeComponent {
ɵcontainerRefreshStart(3);
{
if (ctx.data.right != null) {
let rf0 = ɵembeddedViewStart(0);
let rf0 = ɵembeddedViewStart(0, 1);
{
if (rf0 & ɵRenderFlags.Create) {
ɵelementStart(0, 'tree');
@ -99,6 +100,7 @@ export class TreeFunction {
static ngComponentDef = ɵdefineComponent({
type: TreeFunction,
selectors: [['tree']],
consts: 5,
template: function(rf: ɵRenderFlags, ctx: TreeFunction) {
// bit of a hack
TreeTpl(rf, ctx.data);
@ -128,7 +130,7 @@ export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) {
ɵcontainerRefreshStart(3);
{
if (ctx.left != null) {
let rf0 = ɵembeddedViewStart(0);
let rf0 = ɵembeddedViewStart(0, 5);
{ TreeTpl(rf0, ctx.left); }
ɵembeddedViewEnd();
}
@ -137,7 +139,7 @@ export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) {
ɵcontainerRefreshStart(4);
{
if (ctx.right != null) {
let rf0 = ɵembeddedViewStart(0);
let rf0 = ɵembeddedViewStart(0, 5);
{ TreeTpl(rf0, ctx.right); }
ɵembeddedViewEnd();
}

View File

@ -414,6 +414,7 @@ describe('compiler compliance', () => {
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
template:function MyComponent_Template(rf,ctx){
if (rf & 1) {
$r3$.ɵelementStart(0, "div");
@ -467,6 +468,7 @@ describe('compiler compliance', () => {
selectors: [["child"]],
factory: function ChildComponent_Factory(t) { return new (t || ChildComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
template: function ChildComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵtext(0, "child-view");
@ -493,6 +495,7 @@ describe('compiler compliance', () => {
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelement(0, "child", $c1$);
@ -645,10 +648,11 @@ describe('compiler compliance', () => {
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 3,
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelementStart(0, "ul", null, $c1$);
$r3$.ɵtemplate(2, MyComponent_li_Template_2, null, $c2$);
$r3$.ɵtemplate(2, MyComponent_li_Template_2, 2, null, $c2$);
$r3$.ɵelementEnd();
}
},
@ -705,6 +709,7 @@ describe('compiler compliance', () => {
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
template: function MyApp_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelement(0, "my-comp");
@ -785,6 +790,7 @@ describe('compiler compliance', () => {
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
template: function MyApp_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelement(0, "my-comp");
@ -847,6 +853,7 @@ describe('compiler compliance', () => {
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
template: function MyApp_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelement(0, "object-comp");
@ -913,6 +920,7 @@ describe('compiler compliance', () => {
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
template: function MyApp_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelement(0, "nested-comp");
@ -971,6 +979,7 @@ describe('compiler compliance', () => {
selectors: [["simple"]],
factory: function SimpleComponent_Factory(t) { return new (t || SimpleComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
template: function SimpleComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵprojectionDef();
@ -992,6 +1001,7 @@ describe('compiler compliance', () => {
selectors: [["complex"]],
factory: function ComplexComponent_Factory(t) { return new (t || ComplexComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 4,
template: function ComplexComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵprojectionDef($c1$, $c2$);
@ -1067,6 +1077,7 @@ describe('compiler compliance', () => {
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(0))) && (ctx.someDir = $tmp$.first));
}
},
consts: 2,
template: function ViewQueryComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelement(1, "div", $e0_attrs$);
@ -1134,6 +1145,7 @@ describe('compiler compliance', () => {
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && ($instance$.someDirList = $tmp$));
},
features: [$r3$.ɵPublicFeature],
consts: 2,
template: function ContentQueryComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵprojectionDef();
@ -1219,6 +1231,7 @@ describe('compiler compliance', () => {
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 6,
template: function MyApp_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵtext(0);
@ -1270,6 +1283,7 @@ describe('compiler compliance', () => {
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 3,
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelement(0, "input", null, $c1$);
@ -1345,7 +1359,7 @@ describe('compiler compliance', () => {
if (rf & 1) {
$r3$.ɵelementStart(0, "div");
$r3$.ɵtext(1);
$r3$.ɵtemplate(2, MyComponent_div_span_Template_2, null, $c2$);
$r3$.ɵtemplate(2, MyComponent_div_span_Template_2, 2, null, $c2$);
$r3$.ɵelement(3, "span", null, $c4$);
$r3$.ɵelementEnd();
}
@ -1362,11 +1376,12 @@ describe('compiler compliance', () => {
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 6,
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelement(0, "div", null, $c1$);
$r3$.ɵtext(2);
$r3$.ɵtemplate(3, MyComponent_div_Template_3, null, $c2$);
$r3$.ɵtemplate(3, MyComponent_div_Template_3, 5, null, $c2$);
$r3$.ɵelement(4, "div", null, $c3$);
}
if (rf & 2) {
@ -1430,7 +1445,7 @@ describe('compiler compliance', () => {
if (rf & 1) {
$i0$.ɵelementStart(0, "div");
$i0$.ɵelement(1, "div", null, $c1$);
$i0$.ɵtemplate(3, MyComponent_div_span_Template_3, null, $c2$);
$i0$.ɵtemplate(3, MyComponent_div_span_Template_3, 2, null, $c2$);
$i0$.ɵelementEnd();
}
if (rf & 2) {
@ -1442,7 +1457,7 @@ describe('compiler compliance', () => {
// ...
template:function MyComponent_Template(rf, ctx){
if (rf & 1) {
$i0$.ɵtemplate(0, MyComponent_div_Template_0, null, $c0$);
$i0$.ɵtemplate(0, MyComponent_div_Template_0, 4, null, $c0$);
}
if (rf & 2) {
$i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items));
@ -1506,6 +1521,7 @@ describe('compiler compliance', () => {
factory: function LifecycleComp_Factory(t) { return new (t || LifecycleComp)(); },
inputs: {nameMin: "name"},
features: [$r3$.ɵPublicFeature, $r3$.ɵNgOnChangesFeature],
consts: 0,
template: function LifecycleComp_Template(rf, ctx) {}
});`;
@ -1515,6 +1531,7 @@ describe('compiler compliance', () => {
selectors: [["simple-layout"]],
factory: function SimpleLayout_Factory(t) { return new (t || SimpleLayout)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
template: function SimpleLayout_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelement(0, "lifecycle-comp");
@ -1643,11 +1660,12 @@ describe('compiler compliance', () => {
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
template: function MyComponent_Template(rf, ctx){
if (rf & 1) {
$r3$.ɵnamespaceSVG();
$r3$.ɵelementStart(0,"svg");
$r3$.ɵtemplate(1,MyComponent__svg_g_Template_1,null,$_c0$);
$r3$.ɵtemplate(1, MyComponent__svg_g_Template_1, 2, null, $_c0$);
$r3$.ɵelementEnd();
}
if (rf & 2) { $r3$.ɵelementProperty(1,"forOf",$r3$.ɵbind(ctx.items)); }
@ -1720,10 +1738,11 @@ describe('compiler compliance', () => {
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelementStart(0, "ul");
$r3$.ɵtemplate(1, MyComponent_li_Template_1, null, $_c0$);
$r3$.ɵtemplate(1, MyComponent_li_Template_1, 2, null, $_c0$);
$r3$.ɵelementEnd();
}
if (rf & 2) {
@ -1801,7 +1820,7 @@ describe('compiler compliance', () => {
$r3$.ɵtext(2);
$r3$.ɵelementEnd();
$r3$.ɵelementStart(3, "ul");
$r3$.ɵtemplate(4, MyComponent_li_li_Template_4, null, $c1$);
$r3$.ɵtemplate(4, MyComponent_li_li_Template_4, 2, null, $c1$);
$r3$.ɵelementEnd();
$r3$.ɵelementEnd();
}
@ -1818,10 +1837,11 @@ describe('compiler compliance', () => {
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelementStart(0, "ul");
$r3$.ɵtemplate(1, MyComponent_li_Template_1, null, $c1$);
$r3$.ɵtemplate(1, MyComponent_li_Template_1, 5, null, $c1$);
$r3$.ɵelementEnd();
}
if (rf & 2) {

View File

@ -112,7 +112,7 @@ describe('compiler compliance: listen()', () => {
// ...
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵtemplate(0, MyComponent_div_Template_0, null, $c0$);
$r3$.ɵtemplate(0, MyComponent_div_Template_0, 3, null, $c0$);
}
if (rf & 2) {
$i0$.ɵelementProperty(0, "ngIf", $i0$.ɵbind(ctx.showing));
@ -154,6 +154,7 @@ describe('compiler compliance: listen()', () => {
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 4,
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelementStart(0, "button");

View File

@ -94,6 +94,7 @@ describe('compiler compliance: styling', () => {
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
template: function MyComponent_Template(rf, $ctx$) {
if (rf & 1) {
$r3$.ɵelementStart(0, "div");
@ -151,6 +152,7 @@ describe('compiler compliance: styling', () => {
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelementStart(0, "div");
@ -246,6 +248,7 @@ describe('compiler compliance: styling', () => {
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
template: function MyComponent_Template(rf, $ctx$) {
if (rf & 1) {
$r3$.ɵelementStart(0, "div");
@ -300,6 +303,7 @@ describe('compiler compliance: styling', () => {
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
template: function MyComponent_Template(rf, $ctx$) {
if (rf & 1) {
$r3$.ɵelementStart(0, "div");

View File

@ -81,7 +81,7 @@ describe('compiler compliance: template', () => {
function MyComponent_ul_li_Template_1(rf, ctx) {
if (rf & 1) {
$i0$.ɵelementStart(0, "li");
$i0$.ɵtemplate(1, MyComponent_ul_li_div_Template_1, null, _c0);
$i0$.ɵtemplate(1, MyComponent_ul_li_div_Template_1, 2, null, _c0);
$i0$.ɵelementEnd();
}
if (rf & 2) {
@ -93,7 +93,7 @@ describe('compiler compliance: template', () => {
function MyComponent_ul_Template_0(rf, ctx) {
if (rf & 1) {
$i0$.ɵelementStart(0, "ul");
$i0$.ɵtemplate(1, MyComponent_ul_li_Template_1, null, _c0);
$i0$.ɵtemplate(1, MyComponent_ul_li_Template_1, 2, null, _c0);
$i0$.ɵelementEnd();
}
if (rf & 2) {
@ -104,7 +104,7 @@ describe('compiler compliance: template', () => {
// ...
template:function MyComponent_Template(rf, ctx){
if (rf & 1) {
$i0$.ɵtemplate(0, MyComponent_ul_Template_0, null, _c0);
$i0$.ɵtemplate(0, MyComponent_ul_Template_0, 2, null, _c0);
}
if (rf & 2) {
$i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items));
@ -155,7 +155,7 @@ describe('compiler compliance: template', () => {
// ...
template:function MyComponent_Template(rf, ctx){
if (rf & 1) {
$i0$.ɵtemplate(0, MyComponent_span_Template_0, null, _c0);
$i0$.ɵtemplate(0, MyComponent_span_Template_0, 2, null, _c0);
}
if (rf & 2) {
$i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items));
@ -211,7 +211,7 @@ describe('compiler compliance: template', () => {
function MyComponent_div_Template_0(rf, ctx) {
if (rf & 1) {
$i0$.ɵelementStart(0, "div");
$i0$.ɵtemplate(1, MyComponent_div_span_Template_1, null, $c1$);
$i0$.ɵtemplate(1, MyComponent_div_span_Template_1, 2, null, $c1$);
$i0$.ɵelementEnd();
}
if (rf & 2) {
@ -223,7 +223,7 @@ describe('compiler compliance: template', () => {
// ...
template:function MyComponent_Template(rf, ctx){
if (rf & 1) {
$i0$.ɵtemplate(0, MyComponent_div_Template_0, null, $c0$);
$i0$.ɵtemplate(0, MyComponent_div_Template_0, 2, null, $c0$);
}
if (rf & 2) {
$i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items));
@ -279,7 +279,7 @@ describe('compiler compliance: template', () => {
function MyComponent_div_div_Template_1(rf, ctx) {
if (rf & 1) {
$i0$.ɵelementStart(0, "div");
$i0$.ɵtemplate(1, MyComponent_div_div_div_Template_1, null, _c0);
$i0$.ɵtemplate(1, MyComponent_div_div_div_Template_1, 2, null, _c0);
$i0$.ɵelementEnd();
}
if (rf & 2) {
@ -291,7 +291,7 @@ describe('compiler compliance: template', () => {
function MyComponent_div_Template_0(rf, ctx) {
if (rf & 1) {
$i0$.ɵelementStart(0, "div");
$i0$.ɵtemplate(1, MyComponent_div_div_Template_1, null, _c0);
$i0$.ɵtemplate(1, MyComponent_div_div_Template_1, 2, null, _c0);
$i0$.ɵelementEnd();
}
if (rf & 2) {
@ -302,7 +302,7 @@ describe('compiler compliance: template', () => {
// ...
template:function MyComponent_Template(rf, ctx){
if (rf & 1) {
$i0$.ɵtemplate(0, MyComponent_div_Template_0, null, _c0);
$i0$.ɵtemplate(0, MyComponent_div_Template_0, 2, null, _c0);
}
if (rf & 2) {
$i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items));
@ -348,7 +348,7 @@ describe('compiler compliance: template', () => {
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
$i0$.ɵtemplate(0, Template_0, null, $c0$);
$i0$.ɵtemplate(0, Template_0, 1, null, $c0$);
}
if (rf & 2) {
$i0$.ɵelementProperty(0, "boundAttr", $i0$.ɵbind(ctx.b));

View File

@ -189,13 +189,15 @@ export function compileComponentFromMetadata(
const pipesUsed = new Set<o.Expression>();
const template = meta.template;
const templateFunctionExpression =
new TemplateDefinitionBuilder(
constantPool, BindingScope.ROOT_SCOPE, 0, templateTypeName, templateName,
meta.viewQueries, directiveMatcher, directivesUsed, meta.pipes, pipesUsed,
R3.namespaceHTML)
.buildTemplateFunction(
template.nodes, [], template.hasNgContent, template.ngContentSelectors);
const templateBuilder = new TemplateDefinitionBuilder(
constantPool, BindingScope.ROOT_SCOPE, 0, templateTypeName, templateName, meta.viewQueries,
directiveMatcher, directivesUsed, meta.pipes, pipesUsed, R3.namespaceHTML);
const templateFunctionExpression = templateBuilder.buildTemplateFunction(
template.nodes, [], template.hasNgContent, template.ngContentSelectors);
// e.g. `consts: 2`
definitionMap.set('consts', o.literal(templateBuilder.getSlotCount()));
definitionMap.set('template', templateFunctionExpression);

View File

@ -171,6 +171,10 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
// resolving bindings.
t.visitAll(this, nodes);
// Nested templates must be processed before creation instructions so template()
// instructions can be generated with the correct internal const count.
this._nestedTemplateFns.forEach(buildTemplateFn => buildTemplateFn());
// Generate all the creation mode instructions (e.g. resolve bindings in listeners)
const creationStatements = this._creationCodeFns.map((fn: () => o.Statement) => fn());
@ -208,8 +212,6 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
}
}
this._nestedTemplateFns.forEach(buildTemplateFn => buildTemplateFn());
return o.fn(
// i.e. (rf: RenderFlags, ctx: any)
[new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(CONTEXT_NAME, null)],
@ -727,9 +729,6 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
parameters.push(this.constantPool.getConstLiteral(o.literalArr(attributeNames), true));
}
// e.g. template(1, MyComp_Template_1)
this.creationInstruction(template.sourceSpan, R3.templateCreate, trimTrailingNulls(parameters));
// e.g. p(1, 'forOf', ɵbind(ctx.items));
const context = o.variable(CONTEXT_NAME);
template.inputs.forEach(input => {
@ -756,6 +755,12 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
templateVisitor.buildTemplateFunction(template.children, template.variables);
this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(templateName, null));
});
// e.g. template(1, MyComp_Template_1)
this.creationInstruction(template.sourceSpan, R3.templateCreate, () => {
parameters.splice(2, 0, o.literal(templateVisitor.getSlotCount()));
return trimTrailingNulls(parameters);
});
}
// These should be handled in the template or element directly.
@ -801,6 +806,9 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
}
private allocateDataSlot() { return this._dataIndex++; }
getSlotCount() { return this._dataIndex; }
private bindingContext() { return `${this._bindingContext++}`; }
// Bindings must only be resolved after all local refs have been visited, so all

View File

@ -18,7 +18,7 @@ import {CLEAN_PROMISE, ROOT_DIRECTIVE_INDICES, _getComponentHostLElementNode, ba
import {ComponentDef, ComponentDefInternal, ComponentType} from './interfaces/definition';
import {LElementNode} from './interfaces/node';
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {LViewData, LViewFlags, RootContext, INJECTOR, CONTEXT, TVIEW} from './interfaces/view';
import {LViewData, LViewFlags, RootContext, BINDING_INDEX, INJECTOR, CONTEXT, TVIEW} from './interfaces/view';
import {stringify} from './util';
@ -107,11 +107,12 @@ export function renderComponent<T>(
const rootView: LViewData = createLViewData(
rendererFactory.createRenderer(hostNode, componentDef),
createTView(-1, null, null, null, null), rootContext,
createTView(-1, null, 1, null, null, null), rootContext,
componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways);
rootView[INJECTOR] = opts.injector || null;
const oldView = enterView(rootView, null !);
rootView[BINDING_INDEX] = rootView[TVIEW].bindingStartIndex;
let elementNode: LElementNode;
let component: T;
try {

View File

@ -22,7 +22,7 @@ import {baseDirectiveCreate, createLNode, createLViewData, createTView, elementC
import {ComponentDefInternal, ComponentType, RenderFlags} from './interfaces/definition';
import {LElementNode, TNode, TNodeType} from './interfaces/node';
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
import {BINDING_INDEX, CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
import {RootViewRef, ViewRef} from './view_ref';
export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolver {
@ -121,12 +121,13 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
// Create the root view. Uses empty TView and ContentTemplate.
const rootView: LViewData = createLViewData(
rendererFactory.createRenderer(hostNode, this.componentDef),
createTView(-1, null, null, null, null), rootContext,
createTView(-1, null, 1, null, null, null), rootContext,
this.componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways);
rootView[INJECTOR] = ngModule && ngModule.injector || null;
// rootView is the parent when bootstrapping
const oldView = enterView(rootView, null !);
rootView[BINDING_INDEX] = rootView[TVIEW].bindingStartIndex;
let component: T;
let elementNode: LElementNode;

View File

@ -53,6 +53,15 @@ export function defineComponent<T>(componentDefinition: {
*/
factory: () => T;
/**
* The number of nodes, local refs, and pipes in this component template.
*
* Used to calculate the length of the component's LViewData array, so we
* can pre-fill the array and set the binding start index.
*/
// TODO(kara): remove queries from this count
consts: number;
/**
* Static attributes to set on host element.
*
@ -245,6 +254,7 @@ export function defineComponent<T>(componentDefinition: {
const def: ComponentDefInternal<any> = {
type: type,
diPublic: null,
consts: componentDefinition.consts,
factory: componentDefinition.factory,
template: componentDefinition.template || null !,
hostBindings: componentDefinition.hostBindings || null,

View File

@ -7,7 +7,7 @@
*/
import {assertEqual, assertLessThan} from './assert';
import {NO_CHANGE, _getViewData, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createLNode, getPreviousOrParentNode, getRenderer, initBindings, load, resetApplicationState} from './instructions';
import {NO_CHANGE, _getViewData, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createLNode, getPreviousOrParentNode, getRenderer, load, resetApplicationState} from './instructions';
import {RENDER_PARENT} from './interfaces/container';
import {LContainerNode, LNode, TContainerNode, TElementNode, TNodeType} from './interfaces/node';
import {BINDING_INDEX, HEADER_OFFSET, TVIEW} from './interfaces/view';
@ -293,7 +293,9 @@ function appendI18nNode(node: LNode, parentNode: LNode, previousNode: LNode) {
export function i18nApply(startIndex: number, instructions: I18nInstruction[]): void {
const viewData = _getViewData();
if (ngDevMode) {
assertEqual(viewData[BINDING_INDEX], -1, 'i18nApply should be called before any binding');
assertEqual(
viewData[BINDING_INDEX], viewData[TVIEW].bindingStartIndex,
'i18nApply should be called before any binding');
}
if (!instructions) {
@ -383,7 +385,6 @@ export function i18nExpMapping(
* @returns The concatenated string when any of the arguments changes, `NO_CHANGE` otherwise.
*/
export function i18nInterpolation1(instructions: I18nExpInstruction[], v0: any): string|NO_CHANGE {
initBindings();
const different = bindingUpdated(_getViewData()[BINDING_INDEX]++, v0);
if (!different) {
@ -415,7 +416,6 @@ export function i18nInterpolation1(instructions: I18nExpInstruction[], v0: any):
*/
export function i18nInterpolation2(instructions: I18nExpInstruction[], v0: any, v1: any): string|
NO_CHANGE {
initBindings();
const viewData = _getViewData();
const different = bindingUpdated2(viewData[BINDING_INDEX], v0, v1);
viewData[BINDING_INDEX] += 2;
@ -456,7 +456,6 @@ export function i18nInterpolation2(instructions: I18nExpInstruction[], v0: any,
*/
export function i18nInterpolation3(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any): string|NO_CHANGE {
initBindings();
const viewData = _getViewData();
const different = bindingUpdated3(viewData[BINDING_INDEX], v0, v1, v2);
viewData[BINDING_INDEX] += 3;
@ -499,7 +498,6 @@ export function i18nInterpolation3(
*/
export function i18nInterpolation4(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any): string|NO_CHANGE {
initBindings();
const viewData = _getViewData();
const different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
viewData[BINDING_INDEX] += 4;
@ -544,7 +542,6 @@ export function i18nInterpolation4(
export function i18nInterpolation5(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any): string|
NO_CHANGE {
initBindings();
const viewData = _getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated(viewData[BINDING_INDEX] + 4, v4) || different;
@ -592,7 +589,6 @@ export function i18nInterpolation5(
i18nInterpolation6(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any):
string|NO_CHANGE {
initBindings();
const viewData = _getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated2(viewData[BINDING_INDEX] + 4, v4, v5) || different;
@ -641,7 +637,6 @@ i18nInterpolation6(
export function i18nInterpolation7(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any,
v6: any): string|NO_CHANGE {
initBindings();
const viewData = _getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated3(viewData[BINDING_INDEX] + 4, v4, v5, v6) || different;
@ -691,7 +686,6 @@ export function i18nInterpolation7(
export function i18nInterpolation8(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any,
v6: any, v7: any): string|NO_CHANGE {
initBindings();
const viewData = _getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated4(viewData[BINDING_INDEX] + 4, v4, v5, v6, v7) || different;
@ -733,7 +727,6 @@ export function i18nInterpolation8(
*/
export function i18nInterpolationV(instructions: I18nExpInstruction[], values: any[]): string|
NO_CHANGE {
initBindings();
const viewData = _getViewData();
let different = false;
for (let i = 0; i < values.length; i++) {

View File

@ -518,6 +518,7 @@ export function resetApplicationState() {
*
* @param hostNode Existing node to render into.
* @param templateFn Template function with the instructions.
* @param consts The number of nodes, local refs, and pipes in this template
* @param context to pass into the template.
* @param providedRendererFactory renderer factory to use
* @param host The host element node to use
@ -525,14 +526,14 @@ export function resetApplicationState() {
* @param pipes Pipe defs that should be used for matching
*/
export function renderTemplate<T>(
hostNode: RElement, templateFn: ComponentTemplate<T>, context: T,
hostNode: RElement, templateFn: ComponentTemplate<T>, consts: number, context: T,
providedRendererFactory: RendererFactory3, host: LElementNode | null,
directives?: DirectiveDefListOrFactory | null, pipes?: PipeDefListOrFactory | null,
sanitizer?: Sanitizer | null): LElementNode {
if (host == null) {
resetApplicationState();
rendererFactory = providedRendererFactory;
const tView = getOrCreateTView(templateFn, directives || null, pipes || null, null);
const tView = getOrCreateTView(templateFn, consts, directives || null, pipes || null, null);
host = createLNode(
-1, TNodeType.Element, hostNode, null, null,
createLViewData(
@ -598,6 +599,7 @@ export function renderEmbeddedTemplate<T>(
oldView = enterView(viewNode.data !, viewNode);
namespaceHTML();
viewData[BINDING_INDEX] = tView.bindingStartIndex;
tView.template !(rf, context);
if (rf & RenderFlags.Update) {
refreshDescendantViews();
@ -641,6 +643,7 @@ export function renderComponentOrTemplate<T>(
}
if (templateFn) {
namespaceHTML();
viewData[BINDING_INDEX] = tView.bindingStartIndex;
templateFn(getRenderFlags(hostView), componentOrContext !);
refreshDescendantViews();
} else {
@ -723,8 +726,9 @@ export function element(
*/
export function elementContainerStart(
index: number, attrs?: TAttributes | null, localRefs?: string[] | null): void {
ngDevMode &&
assertEqual(viewData[BINDING_INDEX], -1, 'elements should be created before any bindings');
ngDevMode && assertEqual(
viewData[BINDING_INDEX], tView.bindingStartIndex,
'element containers should be created before any bindings');
ngDevMode && ngDevMode.rendererCreateComment++;
const native = renderer.createComment(ngDevMode ? 'ng-container' : '');
@ -768,8 +772,9 @@ export function elementContainerEnd(): void {
*/
export function elementStart(
index: number, name: string, attrs?: TAttributes | null, localRefs?: string[] | null): void {
ngDevMode &&
assertEqual(viewData[BINDING_INDEX], -1, 'elements should be created before any bindings');
ngDevMode && assertEqual(
viewData[BINDING_INDEX], tView.bindingStartIndex,
'elements should be created before any bindings ');
ngDevMode && ngDevMode.rendererCreateElement++;
@ -1005,8 +1010,9 @@ function saveResolvedLocalsInData(
* @returns TView
*/
function getOrCreateTView(
templateFn: ComponentTemplate<any>, directives: DirectiveDefListOrFactory | null,
pipes: PipeDefListOrFactory | null, viewQuery: ComponentQuery<any>| null): TView {
templateFn: ComponentTemplate<any>, consts: number,
directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null,
viewQuery: ComponentQuery<any>| null): TView {
// TODO(misko): reading `ngPrivateData` here is problematic for two reasons
// 1. It is a megamorphic call on each invocation.
// 2. For nested embedded views (ngFor inside ngFor) the template instance is per
@ -1014,19 +1020,22 @@ function getOrCreateTView(
// Correct solution is to only put `ngPrivateData` on the Component template
// and not on embedded templates.
return templateFn.ngPrivateData || (templateFn.ngPrivateData = createTView(
-1, templateFn, directives, pipes, viewQuery) as never);
return templateFn.ngPrivateData ||
(templateFn.ngPrivateData =
createTView(-1, templateFn, consts, directives, pipes, viewQuery) as never);
}
/**
* Creates a TView instance
*
* @param viewIndex The viewBlockId for inline views, or -1 if it's a component/dynamic
* @param templateFn Template function
* @param consts The number of nodes, local refs, and pipes in this template
* @param directives Registry of directives for this view
* @param pipes Registry of pipes for this view
*/
export function createTView(
viewIndex: number, templateFn: ComponentTemplate<any>| null,
viewIndex: number, templateFn: ComponentTemplate<any>| null, consts: number,
directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null,
viewQuery: ComponentQuery<any>| null): TView {
ngDevMode && ngDevMode.tView++;
@ -1037,7 +1046,7 @@ export function createTView(
node: null !,
data: HEADER_FILLER.slice(), // Fill in to match HEADER_OFFSET in LViewData
childIndex: -1, // Children set in addToViewTree(), if any
bindingStartIndex: -1, // Set in initBindings()
bindingStartIndex: HEADER_OFFSET + consts,
directives: null,
firstTemplatePass: true,
initHooks: null,
@ -1137,7 +1146,8 @@ export function hostElement(
const node = createLNode(
0, TNodeType.Element, rNode, null, null,
createLViewData(
renderer, getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs, def.viewQuery),
renderer, getOrCreateTView(
def.template, def.consts, def.directiveDefs, def.pipeDefs, def.viewQuery),
null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer));
if (firstTemplatePass) {
@ -1590,8 +1600,9 @@ export function elementStylingMap<T>(
* @param value Value to write. This value will be stringified.
*/
export function text(index: number, value?: any): void {
ngDevMode &&
assertEqual(viewData[BINDING_INDEX], -1, 'text nodes should be created before bindings');
ngDevMode && assertEqual(
viewData[BINDING_INDEX], tView.bindingStartIndex,
'text nodes should be created before any bindings');
ngDevMode && ngDevMode.rendererCreateTextNode++;
const textNode = createTextNode(value, renderer);
const node = createLNode(index, TNodeType.Element, textNode, null, null);
@ -1667,7 +1678,8 @@ export function directiveCreate<T>(
function addComponentLogic<T>(
directiveIndex: number, instance: T, def: ComponentDefInternal<T>): void {
const tView = getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs, def.viewQuery);
const tView =
getOrCreateTView(def.template, def.consts, def.directiveDefs, def.pipeDefs, def.viewQuery);
// Only component views should be added to the view tree directly. Embedded views are
// accessed through their containers because they may be removed / re-added later.
@ -1696,8 +1708,9 @@ function addComponentLogic<T>(
export function baseDirectiveCreate<T>(
index: number, directive: T,
directiveDef: DirectiveDefInternal<T>| ComponentDefInternal<T>): T {
ngDevMode &&
assertEqual(viewData[BINDING_INDEX], -1, 'directives should be created before any bindings');
ngDevMode && assertEqual(
viewData[BINDING_INDEX], tView.bindingStartIndex,
'directives should be created before any bindings');
ngDevMode && assertPreviousIsParent();
Object.defineProperty(
@ -1843,6 +1856,7 @@ export function createLContainer(
*
* @param index The index of the container in the data array
* @param templateFn Inline template
* @param consts The number of nodes, local refs, and pipes for this template
* @param tagName The name of the container element, if applicable
* @param attrs The attrs attached to the container, if applicable
* @param localRefs A set of local reference bindings on the element.
@ -1850,14 +1864,15 @@ export function createLContainer(
* Defaults to the current element associated with the local-ref.
*/
export function template(
index: number, templateFn: ComponentTemplate<any>| null, tagName?: string | null,
attrs?: TAttributes | null, localRefs?: string[] | null,
index: number, templateFn: ComponentTemplate<any>| null, consts: number,
tagName?: string | null, attrs?: TAttributes | null, localRefs?: string[] | null,
localRefExtractor?: LocalRefExtractor) {
// TODO: consider a separate node type for templates
const node = containerInternal(index, tagName || null, attrs || null, localRefs || null);
if (firstTemplatePass) {
node.tNode.tViews =
createTView(-1, templateFn, tView.directiveRegistry, tView.pipeRegistry, null);
createTView(-1, templateFn, consts, tView.directiveRegistry, tView.pipeRegistry, null);
}
createDirectivesAndLocals(node, localRefs, localRefExtractor);
@ -1884,9 +1899,9 @@ export function container(index: number): void {
function containerInternal(
index: number, tagName: string | null, attrs: TAttributes | null,
localRefs: string[] | null): LContainerNode {
ngDevMode &&
assertEqual(
viewData[BINDING_INDEX], -1, 'container nodes should be created before any bindings');
ngDevMode && assertEqual(
viewData[BINDING_INDEX], tView.bindingStartIndex,
'container nodes should be created before any bindings');
const currentParent = isParent ? previousOrParentNode : getParentLNode(previousOrParentNode) !;
const lContainer = createLContainer(currentParent, viewData);
@ -2010,7 +2025,7 @@ function scanForView(
* @param viewBlockId The ID of this view
* @return boolean Whether or not this view is in creation mode
*/
export function embeddedViewStart(viewBlockId: number): RenderFlags {
export function embeddedViewStart(viewBlockId: number, consts: number): RenderFlags {
const container =
(isParent ? previousOrParentNode : getParentLNode(previousOrParentNode)) as LContainerNode;
ngDevMode && assertNodeType(container, TNodeType.Container);
@ -2025,8 +2040,8 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags {
} else {
// When we create a new LView, we always reset the state of the instructions.
const newView = createLViewData(
renderer, getOrCreateEmbeddedTView(viewBlockId, container), null, LViewFlags.CheckAlways,
getCurrentSanitizer());
renderer, getOrCreateEmbeddedTView(viewBlockId, consts, container), null,
LViewFlags.CheckAlways, getCurrentSanitizer());
if (lContainer[QUERIES]) {
newView[QUERIES] = lContainer[QUERIES] !.createView();
@ -2042,6 +2057,7 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags {
}
lContainer[ACTIVE_INDEX] !++;
}
viewData[BINDING_INDEX] = tView.bindingStartIndex;
return getRenderFlags(viewNode.data);
}
@ -2053,17 +2069,19 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags {
* it with the same index (since it's in the same template).
*
* @param viewIndex The index of the TView in TNode.tViews
* @param consts The number of nodes, local refs, and pipes in this template
* @param parent The parent container in which to look for the view's static data
* @returns TView
*/
function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TView {
function getOrCreateEmbeddedTView(
viewIndex: number, consts: number, parent: LContainerNode): TView {
ngDevMode && assertNodeType(parent, TNodeType.Container);
const containerTViews = (parent !.tNode as TContainerNode).tViews as TView[];
ngDevMode && assertDefined(containerTViews, 'TView expected');
ngDevMode && assertEqual(Array.isArray(containerTViews), true, 'TViews should be in an array');
if (viewIndex >= containerTViews.length || containerTViews[viewIndex] == null) {
containerTViews[viewIndex] =
createTView(viewIndex, null, tView.directiveRegistry, tView.pipeRegistry, null);
createTView(viewIndex, null, consts, tView.directiveRegistry, tView.pipeRegistry, null);
}
return containerTViews[viewIndex];
}
@ -2443,6 +2461,7 @@ export function detectChangesInternal<T>(
const hostTView = hostView[TVIEW];
const templateFn = hostTView.template !;
const viewQuery = hostTView.viewQuery;
viewData[BINDING_INDEX] = tView.bindingStartIndex;
try {
namespaceHTML();
@ -2501,43 +2520,17 @@ export interface NO_CHANGE {
/** A special value which designates that a value has not changed. */
export const NO_CHANGE = {} as NO_CHANGE;
/**
* Initializes the binding start index. Will get inlined.
*
* This function must be called before any binding related function is called
* (ie `bind()`, `interpolationX()`, `pureFunctionX()`)
*/
export function initBindings() {
// TODO(kara): remove this check when we have pre-filled array
if (tView.bindingStartIndex === -1) {
tView.bindingStartIndex = viewData.length;
}
if (viewData[BINDING_INDEX] === -1) {
viewData[BINDING_INDEX] = tView.bindingStartIndex;
}
}
/**
* Creates a single value binding.
*
* @param value Value to diff
*/
export function bind<T>(value: T): T|NO_CHANGE {
initBindings();
return bindingUpdated(viewData[BINDING_INDEX]++, value) ? value : NO_CHANGE;
}
// TODO(kara): Remove this when updating the compiler (cannot remove without breaking JIT test)
export function reserveSlots(numSlots: number) {
// Init the slots with a unique `NO_CHANGE` value so that the first change is always detected
// whether it happens or not during the first change detection pass - pure functions checks
// might be skipped when short-circuited.
viewData.length += numSlots;
viewData.fill(NO_CHANGE, -numSlots);
// We need to initialize the binding in case a `pureFunctionX` kind of binding instruction is
// called first in the update section.
initBindings();
}
export function reserveSlots(numSlots: number) {}
/**
* Create interpolation bindings with a variable number of expressions.
@ -2554,7 +2547,6 @@ export function reserveSlots(numSlots: number) {
export function interpolationV(values: any[]): string|NO_CHANGE {
ngDevMode && assertLessThan(2, values.length, 'should have at least 3 values');
ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values');
initBindings();
let different = false;
for (let i = 1; i < values.length; i += 2) {
@ -2583,7 +2575,6 @@ export function interpolationV(values: any[]): string|NO_CHANGE {
* @param suffix static value used for concatenation only.
*/
export function interpolation1(prefix: string, v0: any, suffix: string): string|NO_CHANGE {
initBindings();
const different = bindingUpdated(viewData[BINDING_INDEX]++, v0);
return different ? prefix + stringify(v0) + suffix : NO_CHANGE;
}
@ -2591,7 +2582,6 @@ export function interpolation1(prefix: string, v0: any, suffix: string): string|
/** Creates an interpolation binding with 2 expressions. */
export function interpolation2(
prefix: string, v0: any, i0: string, v1: any, suffix: string): string|NO_CHANGE {
initBindings();
const different = bindingUpdated2(viewData[BINDING_INDEX], v0, v1);
viewData[BINDING_INDEX] += 2;
@ -2602,7 +2592,6 @@ export function interpolation2(
export function interpolation3(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): string|
NO_CHANGE {
initBindings();
const different = bindingUpdated3(viewData[BINDING_INDEX], v0, v1, v2);
viewData[BINDING_INDEX] += 3;
@ -2614,7 +2603,6 @@ export function interpolation3(
export function interpolation4(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
suffix: string): string|NO_CHANGE {
initBindings();
const different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
viewData[BINDING_INDEX] += 4;
@ -2628,7 +2616,6 @@ export function interpolation4(
export function interpolation5(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
i3: string, v4: any, suffix: string): string|NO_CHANGE {
initBindings();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated(viewData[BINDING_INDEX] + 4, v4) || different;
viewData[BINDING_INDEX] += 5;
@ -2643,7 +2630,6 @@ export function interpolation5(
export function interpolation6(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
i3: string, v4: any, i4: string, v5: any, suffix: string): string|NO_CHANGE {
initBindings();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated2(viewData[BINDING_INDEX] + 4, v4, v5) || different;
viewData[BINDING_INDEX] += 6;
@ -2659,7 +2645,6 @@ export function interpolation7(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string): string|
NO_CHANGE {
initBindings();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated3(viewData[BINDING_INDEX] + 4, v4, v5, v6) || different;
viewData[BINDING_INDEX] += 7;
@ -2675,7 +2660,6 @@ export function interpolation8(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any,
suffix: string): string|NO_CHANGE {
initBindings();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated4(viewData[BINDING_INDEX] + 4, v4, v5, v6, v7) || different;
viewData[BINDING_INDEX] += 8;

View File

@ -201,6 +201,15 @@ export interface ComponentDef<T, Selector extends string> extends DirectiveDef<T
*/
readonly styles: string[];
/**
* The number of nodes, local refs, and pipes in this component template.
*
* Used to calculate the length of the component's LViewData array, so we
* can pre-fill the array and set the binding start index.
*/
// TODO(kara): remove queries from this count
consts: number;
/**
* Query-related instructions for a component.
*/

View File

@ -6,16 +6,16 @@
* found in the LICENSE file at https://angular.io/license
*/
import {bindingUpdated, bindingUpdated2, bindingUpdated4, updateBinding, getBinding, getCreationMode, getTView, initBindings, bindingUpdated3,} from './instructions';
import {bindingUpdated, bindingUpdated2, bindingUpdated4, updateBinding, getBinding, getCreationMode, getTView, bindingUpdated3,} from './instructions';
/**
* Bindings for pure functions are stored after regular bindings.
*
* ----------------------------------------------------------------------------
* | LNodes ... | regular bindings / interpolations | pure function bindings
* | LNodes / local refs / pipes ... | regular bindings / interpolations | pure function bindings
* ----------------------------------------------------------------------------
* ^
* TView.bindingStartIndex
* ^
* TView.bindingStartIndex
*
* Pure function instructions are given an offset from TView.bindingStartIndex.
* Adding the offset to TView.bindingStartIndex gives the first index where the bindings
@ -32,7 +32,7 @@ import {bindingUpdated, bindingUpdated2, bindingUpdated4, updateBinding, getBind
* @returns value
*/
export function pureFunction0<T>(slotOffset: number, pureFn: () => T, thisArg?: any): T {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return getCreationMode() ?
updateBinding(bindingIndex, thisArg ? pureFn.call(thisArg) : pureFn()) :
@ -51,7 +51,7 @@ export function pureFunction0<T>(slotOffset: number, pureFn: () => T, thisArg?:
*/
export function pureFunction1(
slotOffset: number, pureFn: (v: any) => any, exp: any, thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return bindingUpdated(bindingIndex, exp) ?
updateBinding(bindingIndex + 1, thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) :
@ -72,7 +72,7 @@ export function pureFunction1(
export function pureFunction2(
slotOffset: number, pureFn: (v1: any, v2: any) => any, exp1: any, exp2: any,
thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return bindingUpdated2(bindingIndex, exp1, exp2) ?
updateBinding(
@ -95,7 +95,7 @@ export function pureFunction2(
export function pureFunction3(
slotOffset: number, pureFn: (v1: any, v2: any, v3: any) => any, exp1: any, exp2: any, exp3: any,
thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return bindingUpdated3(bindingIndex, exp1, exp2, exp3) ?
updateBinding(
@ -120,7 +120,7 @@ export function pureFunction3(
export function pureFunction4(
slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any) => any, exp1: any, exp2: any,
exp3: any, exp4: any, thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4) ?
updateBinding(
@ -146,7 +146,7 @@ export function pureFunction4(
export function pureFunction5(
slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any) => any, exp1: any,
exp2: any, exp3: any, exp4: any, exp5: any, thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4);
return bindingUpdated(bindingIndex + 4, exp5) || different ?
@ -174,7 +174,7 @@ export function pureFunction5(
export function pureFunction6(
slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any) => any,
exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4);
return bindingUpdated2(bindingIndex + 4, exp5, exp6) || different ?
@ -204,7 +204,7 @@ export function pureFunction7(
slotOffset: number,
pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any) => any, exp1: any,
exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, exp7: any, thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
let different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4);
return bindingUpdated3(bindingIndex + 4, exp5, exp6, exp7) || different ?
@ -237,7 +237,7 @@ export function pureFunction8(
pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any, v8: any) => any,
exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, exp7: any, exp8: any,
thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
const bindingIndex = getTView().bindingStartIndex + slotOffset;
const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4);
return bindingUpdated4(bindingIndex + 4, exp5, exp6, exp7, exp8) || different ?
@ -263,7 +263,7 @@ export function pureFunction8(
*/
export function pureFunctionV(
slotOffset: number, pureFn: (...v: any[]) => any, exps: any[], thisArg?: any): any {
initBindings(); // TODO(kara): remove this check when we have pre-filled array
// TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings
let bindingIndex = getTView().bindingStartIndex + slotOffset;
let different = false;
for (let i = 0; i < exps.length; i++) {

View File

@ -2349,7 +2349,7 @@
"name": "camelCaseToDashCase"
},
{
"name": "checkAndUpdateBinding$1"
"name": "checkAndUpdateBinding"
},
{
"name": "checkAndUpdateDirectiveDynamic"

View File

@ -641,9 +641,6 @@
{
"name": "hostElement"
},
{
"name": "initBindings"
},
{
"name": "initChangeDetectorIfExisting"
},

View File

@ -314,6 +314,7 @@ describe('InheritDefinitionFeature', () => {
type: SuperComponent,
template: () => {},
selectors: [['', 'superDir', '']],
consts: 0,
factory: () => new SuperComponent()
});
}

View File

@ -35,6 +35,7 @@ describe('iv perf test', () => {
static ngComponentDef = defineComponent({
type: Component,
selectors: [['div']],
consts: 1,
template: function Template(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
container(0);
@ -43,7 +44,7 @@ describe('iv perf test', () => {
containerRefreshStart(0);
{
for (let i = 0; i < count; i++) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 2);
{
if (rf0 & RenderFlags.Create) {
elementStart(0, 'div');

View File

@ -29,6 +29,7 @@ describe('change detection', () => {
type: MyComponent,
selectors: [['my-comp']],
factory: () => new MyComponent(),
consts: 2,
template: (rf: RenderFlags, ctx: MyComponent) => {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
@ -102,6 +103,7 @@ describe('change detection', () => {
type: MyComponent,
selectors: [['my-comp']],
factory: () => comp = new MyComponent(),
consts: 2,
/**
* {{ doCheckCount }} - {{ name }}
* <button (click)="onClick()"></button>
@ -129,6 +131,7 @@ describe('change detection', () => {
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(),
consts: 1,
/** <my-comp [name]="name"></my-comp> */
template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
@ -207,7 +210,7 @@ describe('change detection', () => {
{ listener('click', () => noop()); }
elementEnd();
}
}, [MyComponent]);
}, 2, [MyComponent]);
const buttonParent = renderComponent(ButtonParent);
expect(getRenderedText(buttonParent)).toEqual('1 - Nancy');
@ -229,6 +232,7 @@ describe('change detection', () => {
type: ButtonParent,
selectors: [['button-parent']],
factory: () => parent = new ButtonParent(),
consts: 2,
/** {{ doCheckCount }} - <my-comp></my-comp> */
template: (rf: RenderFlags, ctx: ButtonParent) => {
if (rf & RenderFlags.Create) {
@ -248,7 +252,7 @@ describe('change detection', () => {
if (rf & RenderFlags.Create) {
element(0, 'button-parent');
}
}, [ButtonParent]);
}, 1, [ButtonParent]);
const myButtonApp = renderComponent(MyButtonApp);
expect(parent !.doCheckCount).toEqual(1);
@ -288,6 +292,7 @@ describe('change detection', () => {
type: MyComp,
selectors: [['my-comp']],
factory: () => myComp = new MyComp(injectChangeDetectorRef()),
consts: 1,
/** {{ name }} */
template: (rf: RenderFlags, ctx: MyComp) => {
if (rf & RenderFlags.Create) {
@ -312,6 +317,7 @@ describe('change detection', () => {
type: ParentComp,
selectors: [['parent-comp']],
factory: () => new ParentComp(injectChangeDetectorRef()),
consts: 2,
/**
* {{ doCheckCount}} -
* <my-comp></my-comp>
@ -399,7 +405,7 @@ describe('change detection', () => {
if (rf & RenderFlags.Create) {
element(0, 'my-comp', ['dir', '']);
}
}, [MyComp, Dir]);
}, 1, [MyComp, Dir]);
const app = renderComponent(MyApp);
expect(getRenderedText(app)).toEqual('Nancy');
@ -422,7 +428,7 @@ describe('change detection', () => {
if (rf & RenderFlags.Update) {
textBinding(1, bind(ctx.value));
}
}, [Dir]);
}, 2, [Dir]);
const app = renderComponent(MyApp);
app.value = 'Frank';
@ -445,6 +451,7 @@ describe('change detection', () => {
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(injectChangeDetectorRef()),
consts: 2,
/**
* {{ name}}
* % if (showing) {
@ -461,7 +468,7 @@ describe('change detection', () => {
containerRefreshStart(1);
{
if (ctx.showing) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
element(0, 'div', ['dir', '']);
}
@ -498,6 +505,7 @@ describe('change detection', () => {
type: DetectChangesComp,
selectors: [['detect-changes-comp']],
factory: () => new DetectChangesComp(injectChangeDetectorRef()),
consts: 1,
/** {{ value }} */
template: (rf: RenderFlags, ctx: DetectChangesComp) => {
if (rf & RenderFlags.Create) {
@ -529,6 +537,7 @@ describe('change detection', () => {
type: DetectChangesComp,
selectors: [['detect-changes-comp']],
factory: () => new DetectChangesComp(injectChangeDetectorRef()),
consts: 1,
/** {{ doCheckCount }} */
template: (rf: RenderFlags, ctx: DetectChangesComp) => {
if (rf & RenderFlags.Create) {
@ -557,6 +566,7 @@ describe('change detection', () => {
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(injectChangeDetectorRef()),
consts: 1,
/** <detached-comp></detached-comp> */
template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
@ -579,6 +589,7 @@ describe('change detection', () => {
type: DetachedComp,
selectors: [['detached-comp']],
factory: () => comp = new DetachedComp(injectChangeDetectorRef()),
consts: 1,
/** {{ value }} */
template: (rf: RenderFlags, ctx: DetachedComp) => {
if (rf & RenderFlags.Create) {
@ -678,6 +689,7 @@ describe('change detection', () => {
type: OnPushComp,
selectors: [['on-push-comp']],
factory: () => onPushComp = new OnPushComp(injectChangeDetectorRef()),
consts: 1,
/** {{ value }} */
template: (rf: RenderFlags, ctx: any) => {
if (rf & RenderFlags.Create) {
@ -700,7 +712,7 @@ describe('change detection', () => {
if (rf & RenderFlags.Update) {
elementProperty(0, 'value', bind(ctx.value));
}
}, [OnPushComp]);
}, 1, [OnPushComp]);
const app = renderComponent(OnPushApp);
app.value = 'one';
@ -737,6 +749,7 @@ describe('change detection', () => {
type: OnPushComp,
selectors: [['on-push-comp']],
factory: () => comp = new OnPushComp(injectChangeDetectorRef()),
consts: 1,
/** {{ value }} */
template: (rf: RenderFlags, ctx: OnPushComp) => {
if (rf & RenderFlags.Create) {
@ -757,6 +770,7 @@ describe('change detection', () => {
type: OnPushParent,
selectors: [['on-push-parent']],
factory: () => new OnPushParent(),
consts: 2,
/**
* {{ value }} -
* <on-push-comp></on-push-comp>
@ -825,6 +839,7 @@ describe('change detection', () => {
type: EmbeddedViewParent,
selectors: [['embedded-view-parent']],
factory: () => new EmbeddedViewParent(),
consts: 2,
/**
* {{ value }} -
* % if (ctx.showing) {
@ -841,7 +856,7 @@ describe('change detection', () => {
containerRefreshStart(1);
{
if (ctx.showing) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
element(0, 'on-push-comp');
}
@ -900,6 +915,7 @@ describe('change detection', () => {
type: NoChangesComp,
selectors: [['no-changes-comp']],
factory: () => comp = new NoChangesComp(injectChangeDetectorRef()),
consts: 1,
template: (rf: RenderFlags, ctx: NoChangesComp) => {
if (rf & RenderFlags.Create) {
text(0);
@ -920,6 +936,7 @@ describe('change detection', () => {
type: AppComp,
selectors: [['app-comp']],
factory: () => new AppComp(injectChangeDetectorRef()),
consts: 2,
/**
* {{ value }} -
* <no-changes-comp></no-changes-comp>
@ -981,6 +998,7 @@ describe('change detection', () => {
type: EmbeddedViewApp,
selectors: [['embedded-view-app']],
factory: () => new EmbeddedViewApp(injectChangeDetectorRef()),
consts: 1,
/**
* % if (showing) {
* {{ value }}
@ -994,7 +1012,7 @@ describe('change detection', () => {
containerRefreshStart(0);
{
if (ctx.showing) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
text(0);
}
@ -1064,6 +1082,7 @@ describe('change detection', () => {
type: MyComponent,
selectors: [['my-comp']],
factory: () => new MyComponent(),
consts: 1,
template: (rf: RenderFlags, ctx: MyComponent) => {
if (rf & RenderFlags.Create) {
text(0);

View File

@ -38,13 +38,14 @@ describe('@angular/common integration', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 2,
// <ul>
// <li *ngFor="let item of items">{{item}}</li>
// </ul>
template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
elementStart(0, 'ul');
{ template(1, liTemplate, undefined, ['ngForOf', '']); }
{ template(1, liTemplate, 2, undefined, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -98,6 +99,7 @@ describe('@angular/common integration', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 2,
// <ul>
// <li *ngFor="let item of items; index as index; count as count">{{index}} of
// {{count}}: {{item}}</li>
@ -105,7 +107,7 @@ describe('@angular/common integration', () => {
template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
elementStart(0, 'ul');
{ template(1, liTemplate, undefined, ['ngForOf', '']); }
{ template(1, liTemplate, 2, undefined, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -157,6 +159,7 @@ describe('@angular/common integration', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 4,
// <button (click)="toggle()">Toggle List</button>
// <ul>
// <li *ngFor="let item of items">{{index}}</li>
@ -170,7 +173,7 @@ describe('@angular/common integration', () => {
}
elementEnd();
elementStart(2, 'ul');
{ template(3, liTemplate, undefined, ['ngForOf', '']); }
{ template(3, liTemplate, 2, undefined, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -220,10 +223,11 @@ describe('@angular/common integration', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 2,
template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
elementStart(0, 'ul');
{ template(1, liTemplate, null, ['ngForOf', '']); }
{ template(1, liTemplate, 2, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -238,7 +242,7 @@ describe('@angular/common integration', () => {
function liTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'li');
{ template(1, spanTemplate, null, ['ngForOf', '']); }
{ template(1, spanTemplate, 2, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -309,9 +313,10 @@ describe('@angular/common integration', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 1,
template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
template(0, divTemplate, null, ['ngForOf', '']);
template(0, divTemplate, 2, null, ['ngForOf', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'ngForOf', bind(ctx.items));
@ -325,7 +330,7 @@ describe('@angular/common integration', () => {
function divTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{ template(1, pTemplate, null, ['ngForOf', '']); }
{ template(1, pTemplate, 3, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -401,9 +406,10 @@ describe('@angular/common integration', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 1,
template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
template(0, divTemplate, null, ['ngForOf', '']);
template(0, divTemplate, 2, null, ['ngForOf', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'ngForOf', bind(ctx.items));
@ -417,7 +423,7 @@ describe('@angular/common integration', () => {
function divTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{ template(1, innerDivTemplate, null, ['ngForOf', '']); }
{ template(1, innerDivTemplate, 2, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -429,7 +435,7 @@ describe('@angular/common integration', () => {
function innerDivTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{ template(1, spanTemplate, null, ['ngForOf', '']); }
{ template(1, spanTemplate, 2, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -567,9 +573,10 @@ describe('@angular/common integration', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 1,
template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
template(0, itemTemplate0, null, ['ngForOf', '']);
template(0, itemTemplate0, 2, null, ['ngForOf', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'ngForOf', bind(ctx.items));
@ -583,7 +590,7 @@ describe('@angular/common integration', () => {
function itemTemplate0(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
{ template(1, itemTemplate1, null, ['ngForOf', '']); }
{ template(1, itemTemplate1, 2, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -595,7 +602,7 @@ describe('@angular/common integration', () => {
function itemTemplate1(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
{ template(1, itemTemplate2, null, ['ngForOf', '']); }
{ template(1, itemTemplate2, 2, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -607,7 +614,7 @@ describe('@angular/common integration', () => {
function itemTemplate2(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
{ template(1, itemTemplate3, null, ['ngForOf', '']); }
{ template(1, itemTemplate3, 2, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -619,7 +626,7 @@ describe('@angular/common integration', () => {
function itemTemplate3(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
{ template(1, itemTemplate4, null, ['ngForOf', '']); }
{ template(1, itemTemplate4, 2, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -631,7 +638,7 @@ describe('@angular/common integration', () => {
function itemTemplate4(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
{ template(1, itemTemplate5, null, ['ngForOf', '']); }
{ template(1, itemTemplate5, 2, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -643,7 +650,7 @@ describe('@angular/common integration', () => {
function itemTemplate5(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
{ template(1, itemTemplate6, null, ['ngForOf', '']); }
{ template(1, itemTemplate6, 2, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -655,7 +662,7 @@ describe('@angular/common integration', () => {
function itemTemplate6(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
{ template(1, itemTemplate7, null, ['ngForOf', '']); }
{ template(1, itemTemplate7, 2, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -667,7 +674,7 @@ describe('@angular/common integration', () => {
function itemTemplate7(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
{ template(1, itemTemplate8, null, ['ngForOf', '']); }
{ template(1, itemTemplate8, 2, null, ['ngForOf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -729,14 +736,15 @@ describe('@angular/common integration', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 2,
/**
* <div *ngIf="showing">{{ valueOne }}</div>
* <div *ngIf="showing">{{ valueTwo }}</div>
*/
template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
template(0, templateOne, undefined, ['ngIf', '']);
template(1, templateTwo, undefined, ['ngIf', '']);
template(0, templateOne, 2, undefined, ['ngIf', '']);
template(1, templateTwo, 2, undefined, ['ngIf', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'ngIf', bind(ctx.showing));
@ -801,9 +809,10 @@ describe('@angular/common integration', () => {
type: AppComponent,
factory: () => new AppComponent(),
selectors: [['my-app']],
consts: 1,
template: (rf: RenderFlags, ctx: AppComponent) => {
if (rf & RenderFlags.Create) {
template(0, divTemplate, undefined, ['ngIf', '']);
template(0, divTemplate, 2, undefined, ['ngIf', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'ngIf', bind(ctx.showing));
@ -817,7 +826,7 @@ describe('@angular/common integration', () => {
function divTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{ template(1, outerDivTemplate, undefined, ['ngIf', '']); }
{ template(1, outerDivTemplate, 2, undefined, ['ngIf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -829,7 +838,7 @@ describe('@angular/common integration', () => {
function outerDivTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{ template(1, innerDivTemplate, undefined, ['ngIf', '']); }
{ template(1, innerDivTemplate, 2, undefined, ['ngIf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
@ -870,6 +879,7 @@ describe('@angular/common integration', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 3,
/**
* <ng-template #tpl>from tpl</ng-template>
* <ng-template [ngTemplateOutlet]="showing ? tpl : null"></ng-template>
@ -880,8 +890,8 @@ describe('@angular/common integration', () => {
if (rf1 & RenderFlags.Create) {
text(0, 'from tpl');
}
}, undefined, undefined, ['tpl', ''], templateRefExtractor);
template(2, null, null, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']);
}, 1, undefined, undefined, ['tpl', ''], templateRefExtractor);
template(2, null, 0, null, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']);
}
if (rf & RenderFlags.Update) {
const tplRef = load(1);

View File

@ -32,6 +32,7 @@ describe('components & directives', () => {
type: ChildComponent,
selectors: [['child']],
factory: function ChildComponent_Factory() { return new ChildComponent(); },
consts: 1,
template: function ChildComponent_Template(rf: $RenderFlags$, ctx: $ChildComponent$) {
if (rf & 1) {
$r3$.ɵtext(0, 'child-view');
@ -67,6 +68,7 @@ describe('components & directives', () => {
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent(),
consts: 2,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelement(0, 'child', $e0_attrs$);
@ -120,6 +122,7 @@ describe('components & directives', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'div', $e0_attrs$);
@ -171,6 +174,7 @@ describe('components & directives', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 2,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'button', $e0_attrs$);
@ -218,6 +222,7 @@ describe('components & directives', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'div', $e0_attrs$);
@ -268,6 +273,7 @@ describe('components & directives', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'div', $e0_attrs$);
@ -304,6 +310,7 @@ describe('components & directives', () => {
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory() { return new MyComp(); },
consts: 1,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (rf & 1) {
$r3$.ɵtext(0);
@ -329,6 +336,7 @@ describe('components & directives', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-comp');
@ -393,10 +401,11 @@ describe('components & directives', () => {
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent(),
consts: 3,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'ul', null, $e0_locals$);
$r3$.ɵtemplate(2, C1, '', ['if', '']);
$r3$.ɵtemplate(2, C1, 2, '', ['if', '']);
$r3$.ɵelementEnd();
}
}
@ -425,6 +434,7 @@ describe('components & directives', () => {
type: MyArrayComp,
selectors: [['my-array-comp']],
factory: function MyArrayComp_Factory() { return new MyArrayComp(); },
consts: 1,
template: function MyArrayComp_Template(rf: $RenderFlags$, ctx: $MyArrayComp$) {
if (rf & 1) {
$r3$.ɵtext(0);
@ -456,6 +466,7 @@ describe('components & directives', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-array-comp');
@ -500,6 +511,7 @@ describe('components & directives', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-array-comp');
@ -534,6 +546,7 @@ describe('components & directives', () => {
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory() { return new MyComp(); },
consts: 1,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (rf & 1) {
$r3$.ɵtext(0);
@ -566,6 +579,7 @@ describe('components & directives', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-comp');
@ -609,6 +623,7 @@ describe('components & directives', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-array-comp');
@ -657,6 +672,7 @@ describe('components & directives', () => {
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory() { return new MyComp(); },
consts: 12,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (rf & 1) {
$r3$.ɵtext(0);
@ -720,6 +736,7 @@ describe('components & directives', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
template: function MyApp_Template(rf: $RenderFlags$, c: $any$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-comp');
@ -762,6 +779,7 @@ describe('components & directives', () => {
type: ObjectComp,
selectors: [['object-comp']],
factory: function ObjectComp_Factory() { return new ObjectComp(); },
consts: 4,
template: function ObjectComp_Template(rf: $RenderFlags$, ctx: $ObjectComp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'p');
@ -798,6 +816,7 @@ describe('components & directives', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'object-comp');
@ -839,6 +858,7 @@ describe('components & directives', () => {
type: NestedComp,
selectors: [['nested-comp']],
factory: function NestedComp_Factory() { return new NestedComp(); },
consts: 6,
template: function NestedComp_Template(rf: $RenderFlags$, ctx: $NestedComp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'p');
@ -884,6 +904,7 @@ describe('components & directives', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'nested-comp');

View File

@ -25,6 +25,7 @@ describe('content projection', () => {
type: SimpleComponent,
selectors: [['simple']],
factory: () => new SimpleComponent(),
consts: 1,
template: function(rf: $RenderFlags$, ctx: $SimpleComponent$) {
if (rf & 1) {
$r3$.ɵprojectionDef();
@ -54,6 +55,7 @@ describe('content projection', () => {
type: ComplexComponent,
selectors: [['complex']],
factory: () => new ComplexComponent(),
consts: 4,
template: function(rf: $RenderFlags$, ctx: $ComplexComponent$) {
if (rf & 1) {
$r3$.ɵprojectionDef($pD_0P$, $pD_0R$);
@ -77,6 +79,7 @@ describe('content projection', () => {
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(),
consts: 2,
template: function(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'simple');

View File

@ -37,6 +37,7 @@ describe('elements', () => {
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent(),
consts: 5,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div', $e0_attrs$);
@ -88,6 +89,7 @@ describe('elements', () => {
type: LocalRefComp,
selectors: [['local-ref-comp']],
factory: function LocalRefComp_Factory() { return new LocalRefComp(); },
consts: 4,
template: function LocalRefComp_Template(rf: $RenderFlags$, ctx: $LocalRefComp$) {
let $tmp$: any;
let $tmp_2$: any;
@ -133,6 +135,7 @@ describe('elements', () => {
type: ListenerComp,
selectors: [['listener-comp']],
factory: function ListenerComp_Factory() { return new ListenerComp(); },
consts: 1,
template: function ListenerComp_Template(rf: $RenderFlags$, ctx: $ListenerComp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'button');
@ -188,6 +191,7 @@ describe('elements', () => {
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent(),
consts: 5,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div', $e0_attrs$);
@ -220,6 +224,7 @@ describe('elements', () => {
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
consts: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelement(0, 'div');
@ -251,6 +256,7 @@ describe('elements', () => {
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
consts: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelement(0, 'div');
@ -283,6 +289,7 @@ describe('elements', () => {
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
consts: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
@ -322,6 +329,7 @@ describe('elements', () => {
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
consts: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
@ -373,6 +381,7 @@ describe('elements', () => {
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
consts: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
@ -411,6 +420,7 @@ describe('elements', () => {
type: StyleComponent,
selectors: [['style-comp']],
factory: function StyleComponent_Factory() { return new StyleComponent(); },
consts: 1,
template: function StyleComponent_Template(rf: $RenderFlags$, ctx: $StyleComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');

View File

@ -26,6 +26,7 @@ describe('i18n', () => {
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(),
consts: 2,
template: function(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
@ -51,6 +52,7 @@ describe('i18n', () => {
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(),
consts: 2,
template: function(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
@ -78,6 +80,7 @@ describe('i18n', () => {
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(),
consts: 2,
template: function(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
@ -99,6 +102,18 @@ describe('i18n', () => {
const $i18n_1$ = $r3$.ɵi18nMapping(
$msg_1$, [{START_LI: 1}, {START_LI: 0}], [null, {EXP_1: 1}], ['START_LI']);
function liTemplate(rf1: $RenderFlags$, row: NgForOfContext<string>) {
if (rf1 & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
$r3$.ɵi18nApply(0, $i18n_1$[1]);
}
if (rf1 & 2) {
$r3$.ɵtextBinding(1, $r3$.ɵbind(row.$implicit));
}
}
@Component({
selector: 'my-app',
template: `<ul i18n><li *ngFor="let item of items">value: {{item}}</li></ul>`
@ -109,28 +124,17 @@ describe('i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 2,
template: (rf: $RenderFlags$, myApp: $MyApp$) => {
if (rf & 1) {
$r3$.ɵelementStart(0, 'ul');
$r3$.ɵtemplate(1, liTemplate, null, ['ngForOf', '']);
$r3$.ɵtemplate(1, liTemplate, 2, null, ['ngForOf', '']);
$r3$.ɵelementEnd();
$r3$.ɵi18nApply(1, $i18n_1$[0]);
}
if (rf & 2) {
$r3$.ɵelementProperty(1, 'ngForOf', $r3$.ɵbind(myApp.items));
}
function liTemplate(rf1: $RenderFlags$, row: NgForOfContext<string>) {
if (rf1 & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
$r3$.ɵi18nApply(0, $i18n_1$[1]);
}
if (rf1 & 2) {
$r3$.ɵtextBinding(1, $r3$.ɵbind(row.$implicit));
}
}
},
directives: () => [NgForOf]
});

View File

@ -34,6 +34,7 @@ describe('injection', () => {
factory: function MyComp_Factory() {
return new MyComp($r3$.ɵinjectChangeDetectorRef());
},
consts: 1,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (rf & 1) {
$r3$.ɵtext(0);
@ -51,6 +52,7 @@ describe('injection', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
/** <my-comp></my-comp> */
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
@ -80,6 +82,7 @@ describe('injection', () => {
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory() { return new MyComp($r3$.ɵinjectAttribute('title')); },
consts: 1,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (rf & 1) {
$r3$.ɵtext(0);
@ -97,6 +100,7 @@ describe('injection', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 1,
/** <my-comp></my-comp> */
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
@ -149,6 +153,7 @@ describe('injection', () => {
return new MyApp(
$r3$.ɵdirectiveInject(ServiceA), $r3$.ɵdirectiveInject(ServiceB), inject(INJECTOR));
},
consts: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {},
providers: [ServiceA],
viewProviders: [ServiceB],

View File

@ -46,6 +46,7 @@ describe('lifecycle hooks', () => {
type: LifecycleComp,
selectors: [['lifecycle-comp']],
factory: function LifecycleComp_Factory() { return new LifecycleComp(); },
consts: 0,
template: function LifecycleComp_Template(rf: $RenderFlags$, ctx: $LifecycleComp$) {},
inputs: {nameMin: ['name', 'nameMin']},
features: [$r3$.ɵNgOnChangesFeature]
@ -69,6 +70,7 @@ describe('lifecycle hooks', () => {
type: SimpleLayout,
selectors: [['simple-layout']],
factory: function SimpleLayout_Factory() { return simpleLayout = new SimpleLayout(); },
consts: 2,
template: function SimpleLayout_Template(rf: $RenderFlags$, ctx: $SimpleLayout$) {
if (rf & 1) {
$r3$.ɵelement(0, 'lifecycle-comp');

View File

@ -25,6 +25,7 @@ describe('local references', () => {
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent,
consts: 3,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
let l1_user: any;
if (rf & 1) {
@ -60,11 +61,12 @@ describe('local references', () => {
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent,
consts: 3,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
let l1_tpl: any;
if (rf & 1) {
$r3$.ɵtemplate(
0, MyComponent_Template_0, null, null, ['tpl', ''], $r3$.ɵtemplateRefExtractor);
0, MyComponent_Template_0, 0, null, null, ['tpl', ''], $r3$.ɵtemplateRefExtractor);
$r3$.ɵtext(2);
}
if (rf & 2) {

View File

@ -83,6 +83,7 @@ describe('pipes', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 3,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵtext(0);
@ -155,12 +156,11 @@ describe('pipes', () => {
$r3$.ɵtext(1);
$r3$.ɵpipe(2, 'myPurePipe');
$r3$.ɵelementEnd();
$r3$.ɵreserveSlots(3);
}
if (rf & 2) {
const $comp$ = $r3$.ɵnextContext();
$r3$.ɵtextBinding(
1, $r3$.ɵinterpolation1('', $r3$.ɵpipeBind2(2, 3, $comp$.name, $comp$.size), ''));
1, $r3$.ɵinterpolation1('', $r3$.ɵpipeBind2(2, 3, $comp$.name, $comp$.size), ''));
}
}
@ -178,14 +178,14 @@ describe('pipes', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 5,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵtext(0);
$r3$.ɵpipe(1, 'myPurePipe');
$r3$.ɵtext(2);
$r3$.ɵpipe(3, 'myPurePipe');
$r3$.ɵtemplate(4, MyApp_div_Template_4, '', ['oneTimeIf', '']);
$r3$.ɵreserveSlots(6);
$r3$.ɵtemplate(4, MyApp_div_Template_4, 3, '', ['oneTimeIf', '']);
}
if (rf & 2) {
$r3$.ɵtextBinding(

View File

@ -54,6 +54,7 @@ describe('queries', () => {
type: ViewQueryComponent,
selectors: [['view-query-component']],
factory: function ViewQueryComponent_Factory() { return new ViewQueryComponent(); },
consts: 3,
template: function ViewQueryComponent_Template(
rf: $RenderFlags$, ctx: $ViewQueryComponent$) {
if (rf & 1) {
@ -110,6 +111,7 @@ describe('queries', () => {
type: ContentQueryComponent,
selectors: [['content-query-component']],
factory: function ContentQueryComponent_Factory() { return new ContentQueryComponent(); },
consts: 2,
contentQueries: function ContentQueryComponent_ContentQueries() {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false));
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false));
@ -152,6 +154,7 @@ describe('queries', () => {
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
consts: 2,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'content-query-component');

View File

@ -41,6 +41,7 @@ describe('compiler sanitization', () => {
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
consts: 2,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');

View File

@ -38,6 +38,19 @@ class AppState {
// /NORMATIVE
}
const ToDoAppComponent_NgForOf_Template = function ToDoAppComponent_NgForOf_Template(
rf: $RenderFlags$, ctx1: NgForOfContext<ToDo>) {
if (rf & 1) {
const $comp$ = r3.nextContext();
r3.elementStart(0, 'todo');
r3.listener('archive', $comp$.onArchive.bind($comp$));
r3.elementEnd();
}
if (rf & 2) {
r3.elementProperty(0, 'todo', r3.bind(ctx1.$implicit));
}
};
@Component({
selector: 'todo-app',
template: `
@ -64,24 +77,14 @@ class ToDoAppComponent {
factory: function ToDoAppComponent_Factory() {
return new ToDoAppComponent(r3.directiveInject(AppState));
},
consts: 6,
template: function ToDoAppComponent_Template(rf: $RenderFlags$, ctx: ToDoAppComponent) {
if (rf & 1) {
const ToDoAppComponent_NgForOf_Template = function ToDoAppComponent_NgForOf_Template(
rf: $RenderFlags$, ctx1: NgForOfContext<ToDo>) {
if (rf & 1) {
r3.elementStart(0, 'todo');
r3.listener('archive', ctx.onArchive.bind(ctx));
r3.elementEnd();
}
if (rf & 2) {
r3.elementProperty(0, 'todo', r3.bind(ctx1.$implicit));
}
};
r3.elementStart(0, 'h1');
r3.text(1, 'ToDo Application');
r3.elementEnd();
r3.elementStart(2, 'div');
r3.template(3, ToDoAppComponent_NgForOf_Template, '', ['ngForOf', '']);
r3.template(3, ToDoAppComponent_NgForOf_Template, 1, '', ['ngForOf', '']);
r3.elementEnd();
r3.elementStart(4, 'span');
r3.text(5);
@ -131,6 +134,7 @@ class ToDoItemComponent {
type: ToDoItemComponent,
selectors: [['todo']],
factory: function ToDoItemComponent_Factory() { return new ToDoItemComponent(); },
consts: 6,
template: function ToDoItemComponent_Template(rf: $RenderFlags$, ctx: ToDoItemComponent) {
if (rf & 1) {
r3.elementStart(0, 'div');

View File

@ -85,6 +85,18 @@ describe('template variables', () => {
name: string;
}
function MyComponent_ForOfDirective_Template_1(rf: $RenderFlags$, ctx1: $any$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
}
if (rf & 2) {
const $l0_item$ = ctx1.$implicit;
$r3$.ɵtextBinding(1, $r3$.ɵinterpolation1('', $l0_item$.name, ''));
}
}
@Component({
selector: 'my-component',
template: `<ul><li *for="let item of items">{{item.name}}</li></ul>`
@ -97,29 +109,15 @@ describe('template variables', () => {
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
consts: 2,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'ul');
$r3$.ɵtemplate(1, MyComponent_ForOfDirective_Template_1, '', ['forOf', '']);
$r3$.ɵtemplate(1, MyComponent_ForOfDirective_Template_1, 2, '', ['forOf', '']);
$r3$.ɵelementEnd();
}
if (rf & 2) {
$r3$.ɵelementProperty(1, 'forOf', $r3$.ɵbind(ctx.items));
$r3$.ɵcontainerRefreshStart(1);
$r3$.ɵcontainerRefreshEnd();
}
function MyComponent_ForOfDirective_Template_1(rf: $RenderFlags$, ctx1: $any$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
}
let $l0_item$: any;
if (rf & 2) {
$l0_item$ = ctx1.$implicit;
$r3$.ɵtextBinding(1, $r3$.ɵinterpolation1('', $l0_item$.name, ''));
}
}
}
});
@ -146,6 +144,39 @@ describe('template variables', () => {
infos: Info[];
}
function MyComponent_ForOfDirective_Template_1(rf: $RenderFlags$, ctx1: $any$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵelementStart(1, 'div');
$r3$.ɵtext(2);
$r3$.ɵelementEnd();
$r3$.ɵelementStart(3, 'ul');
$r3$.ɵtemplate(
4, MyComponent_ForOfDirective_ForOfDirective_Template_3, 2, '', ['forOf', '']);
$r3$.ɵelementEnd();
$r3$.ɵelementEnd();
}
if (rf & 2) {
const $l0_item$ = ctx1.$implicit;
$r3$.ɵelementProperty(4, 'forOf', $r3$.ɵbind($l0_item$.infos));
$r3$.ɵtextBinding(2, $r3$.ɵinterpolation1('', $l0_item$.name, ''));
}
}
function MyComponent_ForOfDirective_ForOfDirective_Template_3(rf: $number$, ctx2: $any$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
}
if (rf & 2) {
const $l0_info$ = ctx2.$implicit;
const $l0_item$ = $r3$.ɵnextContext();
$r3$.ɵtextBinding(
1, $r3$.ɵinterpolation2(' ', $l0_item$.name, ': ', $l0_info$.description, ' '));
}
}
@Component({
selector: 'my-component',
template: `
@ -171,10 +202,11 @@ describe('template variables', () => {
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
consts: 2,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'ul');
$r3$.ɵtemplate(1, MyComponent_ForOfDirective_Template_1, '', ['forOf', '']);
$r3$.ɵtemplate(1, MyComponent_ForOfDirective_Template_1, 5, '', ['forOf', '']);
$r3$.ɵelementEnd();
}
if (rf & 2) {
@ -182,43 +214,6 @@ describe('template variables', () => {
$r3$.ɵcontainerRefreshStart(1);
$r3$.ɵcontainerRefreshEnd();
}
function MyComponent_ForOfDirective_Template_1(rf1: $RenderFlags$, ctx1: $any$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵelementStart(1, 'div');
$r3$.ɵtext(2);
$r3$.ɵelementEnd();
$r3$.ɵelementStart(3, 'ul');
$r3$.ɵtemplate(
4, MyComponent_ForOfDirective_ForOfDirective_Template_3, '', ['forOf', '']);
$r3$.ɵelementEnd();
$r3$.ɵelementEnd();
}
let $l0_item$: any;
if (rf & 2) {
$l0_item$ = ctx1.$implicit;
$r3$.ɵelementProperty(4, 'forOf', $r3$.ɵbind($l0_item$.infos));
$r3$.ɵtextBinding(2, $r3$.ɵinterpolation1('', $l0_item$.name, ''));
$r3$.ɵcontainerRefreshStart(4);
$r3$.ɵcontainerRefreshEnd();
}
function MyComponent_ForOfDirective_ForOfDirective_Template_3(
rf2: $number$, ctx2: $any$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
}
let $l0_info$: any;
if (rf & 2) {
$l0_info$ = ctx2.$implicit;
$r3$.ɵtextBinding(
1, $r3$.ɵinterpolation2(' ', $l0_item$.name, ': ', $l0_info$.description, ' '));
}
}
}
}
});
// /NORMATIVE

View File

@ -27,6 +27,7 @@ describe('component', () => {
static ngComponentDef = defineComponent({
type: CounterComponent,
selectors: [['counter']],
consts: 1,
template: function(rf: RenderFlags, ctx: CounterComponent) {
if (rf & RenderFlags.Create) {
text(0);
@ -72,6 +73,7 @@ describe('component', () => {
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent(directiveInject(MyService)),
consts: 1,
template: function(fs: RenderFlags, ctx: MyComponent) {
if (fs & RenderFlags.Create) {
text(0);
@ -114,7 +116,7 @@ describe('component with a container', () => {
containerRefreshStart(0);
{
for (const item of ctx.items) {
const rf0 = embeddedViewStart(0);
const rf0 = embeddedViewStart(0, 1);
{
if (rf0 & RenderFlags.Create) {
text(0);
@ -136,6 +138,7 @@ describe('component with a container', () => {
static ngComponentDef = defineComponent({
type: WrapperComponent,
selectors: [['wrapper']],
consts: 1,
template: function ChildComponentTemplate(rf: RenderFlags, ctx: {items: string[]}) {
if (rf & RenderFlags.Create) {
container(0);
@ -143,7 +146,7 @@ describe('component with a container', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(0);
{
const rf0 = embeddedViewStart(0);
const rf0 = embeddedViewStart(0, 1);
{ showItems(rf0, {items: ctx.items}); }
embeddedViewEnd();
}
@ -168,10 +171,10 @@ describe('component with a container', () => {
it('should re-render on input change', () => {
const ctx: {items: string[]} = {items: ['a']};
expect(renderToHtml(template, ctx, defs)).toEqual('<wrapper>a</wrapper>');
expect(renderToHtml(template, ctx, 1, defs)).toEqual('<wrapper>a</wrapper>');
ctx.items = [...ctx.items, 'b'];
expect(renderToHtml(template, ctx, defs)).toEqual('<wrapper>ab</wrapper>');
expect(renderToHtml(template, ctx, 1, defs)).toEqual('<wrapper>ab</wrapper>');
});
});
@ -183,6 +186,7 @@ describe('encapsulation', () => {
static ngComponentDef = defineComponent({
type: WrapperComponent,
selectors: [['wrapper']],
consts: 1,
template: function(rf: RenderFlags, ctx: WrapperComponent) {
if (rf & RenderFlags.Create) {
element(0, 'encapsulated');
@ -197,6 +201,7 @@ describe('encapsulation', () => {
static ngComponentDef = defineComponent({
type: EncapsulatedComponent,
selectors: [['encapsulated']],
consts: 2,
template: function(rf: RenderFlags, ctx: EncapsulatedComponent) {
if (rf & RenderFlags.Create) {
text(0, 'foo');
@ -215,6 +220,7 @@ describe('encapsulation', () => {
static ngComponentDef = defineComponent({
type: LeafComponent,
selectors: [['leaf']],
consts: 2,
template: function(rf: RenderFlags, ctx: LeafComponent) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
@ -245,6 +251,7 @@ describe('encapsulation', () => {
static ngComponentDef = defineComponent({
type: WrapperComponentWith,
selectors: [['wrapper']],
consts: 1,
template: function(rf: RenderFlags, ctx: WrapperComponentWith) {
if (rf & RenderFlags.Create) {
element(0, 'leaf');
@ -262,6 +269,7 @@ describe('encapsulation', () => {
static ngComponentDef = defineComponent({
type: LeafComponentwith,
selectors: [['leaf']],
consts: 1,
template: function(rf: RenderFlags, ctx: LeafComponentwith) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
@ -320,6 +328,7 @@ describe('recursive components', () => {
type: TreeComponent,
selectors: [['tree-comp']],
factory: () => new TreeComponent(),
consts: 3,
template: (rf: RenderFlags, ctx: TreeComponent) => {
if (rf & RenderFlags.Create) {
text(0);
@ -331,7 +340,7 @@ describe('recursive components', () => {
containerRefreshStart(1);
{
if (ctx.data.left != null) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
element(0, 'tree-comp');
}
@ -345,7 +354,7 @@ describe('recursive components', () => {
containerRefreshStart(2);
{
if (ctx.data.right != null) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
element(0, 'tree-comp');
}
@ -379,12 +388,13 @@ describe('recursive components', () => {
type: NgIfTree,
selectors: [['ng-if-tree']],
factory: () => new NgIfTree(),
consts: 3,
template: (rf: RenderFlags, ctx: NgIfTree) => {
if (rf & RenderFlags.Create) {
text(0);
template(1, IfTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']);
template(2, IfTemplate2, '', [AttributeMarker.SelectOnly, 'ngIf']);
template(1, IfTemplate, 1, '', [AttributeMarker.SelectOnly, 'ngIf']);
template(2, IfTemplate2, 1, '', [AttributeMarker.SelectOnly, 'ngIf']);
}
if (rf & RenderFlags.Update) {
textBinding(0, bind(ctx.data.value));
@ -453,7 +463,7 @@ describe('recursive components', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(0);
if (!ctx.skipContent) {
const rf0 = embeddedViewStart(0);
const rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
elementStart(0, 'tree-comp');
elementEnd();
@ -462,7 +472,7 @@ describe('recursive components', () => {
}
containerRefreshEnd();
}
}, [TreeComponent]);
}, 1, [TreeComponent]);
const fixture = new ComponentFixture(App);
expect(getRenderedText(fixture.component)).toEqual('6201534');
@ -487,7 +497,7 @@ describe('recursive components', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(0);
if (!ctx.skipContent) {
const rf0 = embeddedViewStart(0);
const rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
elementStart(0, 'ng-if-tree');
elementEnd();
@ -496,7 +506,7 @@ describe('recursive components', () => {
}
containerRefreshEnd();
}
}, [NgIfTree]);
}, 1, [NgIfTree]);
const fixture = new ComponentFixture(App);
expect(getRenderedText(fixture.component)).toEqual('6201534');
@ -516,6 +526,7 @@ describe('recursive components', () => {
type: TestInputsComponent,
selectors: [['test-inputs']],
inputs: {minifiedName: 'unminifiedName'},
consts: 0,
factory: () => new TestInputsComponent(),
template: function(rf: RenderFlags, ctx: TestInputsComponent): void {
// Template not needed for this test

View File

@ -31,7 +31,7 @@ describe('content projection', () => {
{ projection(1); }
elementEnd();
}
});
}, 2);
/**
* <child>content</child>
@ -42,7 +42,7 @@ describe('content projection', () => {
{ text(1, 'content'); }
elementEnd();
}
}, [Child]);
}, 2, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child><div>content</div></child>');
@ -55,7 +55,7 @@ describe('content projection', () => {
projectionDef();
projection(0);
}
});
}, 1);
/** <child>content</child> */
const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
@ -64,7 +64,7 @@ describe('content projection', () => {
{ text(1, 'content'); }
elementEnd();
}
}, [Child]);
}, 2, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child>content</child>');
@ -77,7 +77,7 @@ describe('content projection', () => {
projectionDef();
projection(0);
}
});
}, 1);
/**
* <child>
@ -98,7 +98,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 5, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child>before<div>content</div>after</child>');
@ -113,7 +113,7 @@ describe('content projection', () => {
{ projection(1); }
elementEnd();
}
});
}, 2);
/** <grand-child><ng-content></ng-content></grand-child> */
const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
@ -123,7 +123,7 @@ describe('content projection', () => {
{ projection(1); }
elementEnd();
}
}, [GrandChild]);
}, 2, [GrandChild]);
/** <child><b>Hello</b>World!</child> */
const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
@ -137,7 +137,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 4, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent))
@ -154,13 +154,13 @@ describe('content projection', () => {
{ projection(1); }
elementEnd();
}
});
}, 2);
const ProjectedComp = createComponent('projected-comp', (rf: RenderFlags, ctx: any) => {
if (rf & RenderFlags.Create) {
text(0, 'content');
}
});
}, 1);
/**
* <child>
@ -173,7 +173,7 @@ describe('content projection', () => {
{ element(1, 'projected-comp'); }
elementEnd();
}
}, [Child, ProjectedComp]);
}, 2, [Child, ProjectedComp]);
const parent = renderComponent(Parent);
expect(toHtml(parent))
@ -189,7 +189,7 @@ describe('content projection', () => {
{ projection(1); }
elementEnd();
}
});
}, 2);
/** <p><ng-content></ng-content></p> */
const ProjectedComp = createComponent('projected-comp', (rf: RenderFlags, ctx: any) => {
@ -199,7 +199,7 @@ describe('content projection', () => {
projection(1);
elementEnd();
}
});
}, 2);
/**
* <child>
@ -225,7 +225,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child, ProjectedComp]);
}, 5, [Child, ProjectedComp]);
const parent = renderComponent(Parent);
expect(toHtml(parent))
@ -242,7 +242,7 @@ describe('content projection', () => {
{ projection(1); }
elementEnd();
}
});
}, 2);
/**
* <child>
@ -267,7 +267,7 @@ describe('content projection', () => {
containerRefreshStart(2);
{
if (ctx.value) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
text(0, 'content');
}
@ -276,7 +276,7 @@ describe('content projection', () => {
}
containerRefreshEnd();
}
}, [Child]);
}, 4, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child><div>()</div></child>');
@ -297,7 +297,7 @@ describe('content projection', () => {
projectionDef();
projection(0);
}
});
}, 1);
/**
* <child>
@ -316,7 +316,7 @@ describe('content projection', () => {
containerRefreshStart(1);
{
if (ctx.value) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
text(0, 'content');
}
@ -325,7 +325,7 @@ describe('content projection', () => {
}
containerRefreshEnd();
}
}, [Child]);
}, 2, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child></child>');
@ -348,7 +348,7 @@ describe('content projection', () => {
{ projection(1); }
elementEnd();
}
});
}, 2);
/**
* <child>
@ -375,13 +375,13 @@ describe('content projection', () => {
containerRefreshStart(2);
{
if (ctx.value) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
text(0, 'content');
}
embeddedViewEnd();
} else {
if (embeddedViewStart(1)) {
if (embeddedViewStart(1, 1)) {
text(0, 'else');
}
embeddedViewEnd();
@ -389,7 +389,7 @@ describe('content projection', () => {
}
containerRefreshEnd();
}
}, [Child]);
}, 4, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child><div>(else)</div></child>');
@ -424,7 +424,7 @@ describe('content projection', () => {
containerRefreshStart(1);
{
if (!ctx.skipContent) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 2);
if (rf0 & RenderFlags.Create) {
elementStart(0, 'span');
projection(1);
@ -457,7 +457,7 @@ describe('content projection', () => {
// testing
childCmptInstance = loadDirective(0);
}
}, [Child]);
}, 4, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child><div><span><div>text</div>content</span></div></child>');
@ -489,7 +489,7 @@ describe('content projection', () => {
containerRefreshStart(1);
{
if (!ctx.skipContent) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 2);
if (rf0 & RenderFlags.Create) {
projection(0);
text(1, 'text');
@ -499,7 +499,7 @@ describe('content projection', () => {
}
containerRefreshEnd();
}
});
}, 2);
/** <child></child> */
const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
@ -509,7 +509,7 @@ describe('content projection', () => {
// testing
childCmptInstance = loadDirective(0);
}
}, [Child]);
}, 1, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child><div>text</div></child>');
@ -541,7 +541,7 @@ describe('content projection', () => {
containerRefreshStart(1);
{
if (!ctx.skipContent) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
projection(0);
}
@ -550,7 +550,7 @@ describe('content projection', () => {
}
containerRefreshEnd();
}
});
}, 2);
/**
* <child>content</child>
@ -564,7 +564,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 2, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child><div>content</div></child>');
@ -599,7 +599,7 @@ describe('content projection', () => {
containerRefreshStart(2);
{
if (!ctx.skipContent) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
projection(0);
}
@ -608,7 +608,7 @@ describe('content projection', () => {
}
containerRefreshEnd();
}
});
}, 4);
/**
* <child>
@ -633,7 +633,7 @@ describe('content projection', () => {
containerRefreshStart(2);
{
if (!ctx.skipContent) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
text(0, 'content');
}
@ -642,7 +642,7 @@ describe('content projection', () => {
}
containerRefreshEnd();
}
}, [Child]);
}, 4, [Child]);
const fixture = new ComponentFixture(Parent);
expect(fixture.html)
@ -675,7 +675,7 @@ describe('content projection', () => {
containerRefreshStart(1);
{
if (!ctx.skipContent) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
projection(0);
}
@ -684,7 +684,7 @@ describe('content projection', () => {
}
containerRefreshEnd();
}
});
}, 2);
/**
* <child>
@ -710,7 +710,7 @@ describe('content projection', () => {
containerRefreshStart(2);
{
if (!ctx.skipContent) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
projection(0);
}
@ -719,7 +719,7 @@ describe('content projection', () => {
}
containerRefreshEnd();
}
}, [Child]);
}, 4, [Child]);
let parent: any;
/** <parent><p>text</p></parent> */
@ -735,7 +735,7 @@ describe('content projection', () => {
// testing
parent = loadDirective(0);
}
}, [Parent]);
}, 3, [Parent]);
const fixture = new ComponentFixture(App);
expect(fixture.html)
@ -769,7 +769,7 @@ describe('content projection', () => {
containerRefreshStart(1);
{
if (!ctx.skipContent) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 3);
if (rf0 & RenderFlags.Create) {
text(0, 'before-');
projection(1);
@ -780,7 +780,7 @@ describe('content projection', () => {
}
containerRefreshEnd();
}
});
}, 2);
/**
* <child>content</child>
@ -794,7 +794,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 2, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child><div>before-content-after</div></child>');
@ -816,14 +816,14 @@ describe('content projection', () => {
if (rf & RenderFlags.Create) {
projectionDef();
text(0, 'Before-');
template(1, IfTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']);
template(1, IfTemplate, 1, '', [AttributeMarker.SelectOnly, 'ngIf']);
text(2, '-After');
}
if (rf & RenderFlags.Update) {
elementProperty(1, 'ngIf', bind(ctx.showing));
}
}, [NgIf]);
}, 3, [NgIf]);
function IfTemplate(rf1: RenderFlags, ctx: any) {
if (rf1 & RenderFlags.Create) {
@ -853,7 +853,7 @@ describe('content projection', () => {
// testing
child = loadDirective(0);
}
}, [Child]);
}, 4, [Child]);
const fixture = new ComponentFixture(App);
child !.showing = true;
@ -881,14 +881,14 @@ describe('content projection', () => {
if (rf & RenderFlags.Create) {
projectionDef();
text(0, 'Before-');
template(1, IfTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']);
template(1, IfTemplate, 1, '', [AttributeMarker.SelectOnly, 'ngIf']);
text(2, '-After');
}
if (rf & RenderFlags.Update) {
elementProperty(1, 'ngIf', bind(ctx.showing));
}
}, [NgIf]);
}, 3, [NgIf]);
function IfTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
@ -918,7 +918,7 @@ describe('content projection', () => {
// testing
child = loadDirective(0);
}
}, [Child]);
}, 4, [Child]);
const fixture = new ComponentFixture(App);
child !.showing = true;
@ -949,7 +949,7 @@ describe('content projection', () => {
{ projection(3); }
elementEnd();
}
});
}, 4);
/**
* <child>content</child>
@ -960,7 +960,7 @@ describe('content projection', () => {
{ text(1, 'content'); }
elementEnd();
}
}, [Child]);
}, 2, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child><div></div><span>content</span></child>');
@ -997,7 +997,7 @@ describe('content projection', () => {
containerRefreshStart(2);
{
if (ctx.show) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
projection(0);
}
@ -1006,7 +1006,7 @@ describe('content projection', () => {
}
containerRefreshEnd();
}
});
}, 3);
/**
* <child>content</child>
@ -1020,7 +1020,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 2, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child>content<div></div></child>');
@ -1038,7 +1038,7 @@ describe('content projection', () => {
projection(1);
text(2, 'After');
}
});
}, 3);
/**
* <projection-comp>
@ -1073,7 +1073,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [ProjectionComp]);
}, 10, [ProjectionComp]);
const fixture = new ComponentFixture(AppComp);
fixture.update();
@ -1096,7 +1096,7 @@ describe('content projection', () => {
projection(1);
text(2, 'After');
}
});
}, 3);
/**
* <projection-comp>
@ -1134,7 +1134,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [ProjectionComp]);
}, 11, [ProjectionComp]);
/**
* <parent-comp>
@ -1153,7 +1153,7 @@ describe('content projection', () => {
{ text(3, '**DEF**'); }
elementEnd();
}
}, [ProjectionParent]);
}, 4, [ProjectionParent]);
const fixture = new ComponentFixture(AppComp);
fixture.update();
@ -1175,7 +1175,7 @@ describe('content projection', () => {
projectionDef();
projection(0);
}
});
}, 1);
`<child>
<ng-container>
@ -1198,7 +1198,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 4, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child>content</child>');
@ -1212,7 +1212,7 @@ describe('content projection', () => {
projectionDef();
projection(0);
}
});
}, 1);
`<grand-child>
<ng-content></ng-content>
@ -1224,7 +1224,7 @@ describe('content projection', () => {
{ projection(1); }
elementEnd();
}
}, [GrandChild]);
}, 2, [GrandChild]);
`<child>
<ng-container>
@ -1247,7 +1247,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 4, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child><grand-child>content</grand-child></child>');
@ -1272,7 +1272,7 @@ describe('content projection', () => {
{ projection(3, 2); }
elementEnd();
}
});
}, 4);
/**
* <child>
@ -1293,7 +1293,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 5, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent))
@ -1311,7 +1311,7 @@ describe('content projection', () => {
projectionDef([[['', 'title', '']]], ['[title]']);
{ projection(0, 1); }
}
});
}, 1);
/**
* <child>
@ -1331,7 +1331,7 @@ describe('content projection', () => {
if (rf & RenderFlags.Update) {
elementProperty(1, 'title', bind('Some title'));
}
}, [Child]);
}, 3, [Child]);
const fixture = new ComponentFixture(Parent);
expect(fixture.html).toEqual('<child><span title="Some title">Has title</span></child>');
@ -1358,7 +1358,7 @@ describe('content projection', () => {
{ projection(3, 2); }
elementEnd();
}
});
}, 4);
/**
* <child>
@ -1379,7 +1379,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 5, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent))
@ -1407,7 +1407,7 @@ describe('content projection', () => {
{ projection(3, 2); }
elementEnd();
}
});
}, 4);
/**
* <child>
@ -1428,7 +1428,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 5, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent))
@ -1452,7 +1452,7 @@ describe('content projection', () => {
{ projection(3, 2); }
elementEnd();
}
});
}, 4);
/**
* <child>
@ -1473,7 +1473,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 5, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent))
@ -1496,7 +1496,7 @@ describe('content projection', () => {
{ projection(3); }
elementEnd();
}
});
}, 4);
/**
* <child>
@ -1518,7 +1518,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 6, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent))
@ -1541,7 +1541,7 @@ describe('content projection', () => {
{ projection(3, 1); }
elementEnd();
}
});
}, 4);
/**
* <child>
@ -1564,7 +1564,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 6, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent))
@ -1590,7 +1590,7 @@ describe('content projection', () => {
element(1, 'hr');
projection(2);
}
});
}, 3);
/**
* <grand-child>
@ -1610,7 +1610,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [GrandChild]);
}, 4, [GrandChild]);
/**
* <child>
@ -1629,7 +1629,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 3, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent))
@ -1653,7 +1653,7 @@ describe('content projection', () => {
element(1, 'hr');
projection(2, 2);
}
});
}, 3);
/**
* <card>
@ -1673,7 +1673,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Card]);
}, 4, [Card]);
/**
* <card-with-title>
@ -1686,7 +1686,7 @@ describe('content projection', () => {
{ text(1, 'content'); }
elementEnd();
}
}, [CardWithTitle]);
}, 2, [CardWithTitle]);
const app = renderComponent(App);
expect(toHtml(app))
@ -1711,7 +1711,7 @@ describe('content projection', () => {
element(1, 'hr');
projection(2, 2);
}
});
}, 3);
/**
* <card>
@ -1731,7 +1731,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Card]);
}, 4, [Card]);
/**
* <card-with-title>
@ -1744,7 +1744,7 @@ describe('content projection', () => {
{ text(1, 'content'); }
elementEnd();
}
}, [CardWithTitle]);
}, 2, [CardWithTitle]);
const app = renderComponent(App);
expect(toHtml(app))
@ -1762,7 +1762,7 @@ describe('content projection', () => {
projectionDef([[['div']]], ['div']);
projection(0, 1);
}
});
}, 1);
/**
* <child>
@ -1783,7 +1783,7 @@ describe('content projection', () => {
}
elementEnd();
}
}, [Child]);
}, 5, [Child]);
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child><div>should project</div></child>');
@ -1803,7 +1803,7 @@ describe('content projection', () => {
{ projection(1, 1); }
elementEnd();
}
});
}, 2);
function IfTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
@ -1821,13 +1821,13 @@ describe('content projection', () => {
const Parent = createComponent('parent', function(rf: RenderFlags, ctx: {value: any}) {
if (rf & RenderFlags.Create) {
elementStart(0, 'child');
{ template(1, IfTemplate, 'div', [AttributeMarker.SelectOnly, 'ngIf']); }
{ template(1, IfTemplate, 2, 'div', [AttributeMarker.SelectOnly, 'ngIf']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
elementProperty(1, 'ngIf', bind(ctx.value));
}
}, [Child, NgIf]);
}, 2, [Child, NgIf]);
const fixture = new ComponentFixture(Parent);

View File

@ -14,9 +14,7 @@ import {ComponentFixture, TemplateFixture, createComponent, renderToHtml} from '
describe('JS control flow', () => {
it('should work with if block', () => {
const ctx: {message: string | null, condition: boolean} = {message: 'Hello', condition: true};
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{ container(1); }
@ -26,7 +24,7 @@ describe('JS control flow', () => {
containerRefreshStart(1);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 2);
{
if (rf1 & RenderFlags.Create) {
elementStart(0, 'span');
@ -42,21 +40,25 @@ describe('JS control flow', () => {
}
}
containerRefreshEnd();
}
}, 2);
expect(renderToHtml(Template, ctx)).toEqual('<div><span>Hello</span></div>');
const fixture = new ComponentFixture(App);
fixture.component.condition = true;
fixture.component.message = 'Hello';
fixture.update();
expect(fixture.html).toEqual('<div><span>Hello</span></div>');
ctx.condition = false;
ctx.message = 'Hi!';
expect(renderToHtml(Template, ctx)).toEqual('<div></div>');
fixture.component.condition = false;
fixture.component.message = 'Hi!';
fixture.update();
expect(fixture.html).toEqual('<div></div>');
ctx.condition = true;
expect(renderToHtml(Template, ctx)).toEqual('<div><span>Hi!</span></div>');
fixture.component.condition = true;
fixture.update();
expect(fixture.html).toEqual('<div><span>Hi!</span></div>');
});
it('should work with nested if blocks', () => {
const ctx: {condition: boolean, condition2: boolean} = {condition: true, condition2: true};
/**
* <div>
* % if(ctx.condition) {
@ -68,7 +70,7 @@ describe('JS control flow', () => {
* % }
* </div>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{ container(1); }
@ -78,7 +80,7 @@ describe('JS control flow', () => {
containerRefreshStart(1);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 2);
{
if (rf1 & RenderFlags.Create) {
elementStart(0, 'span');
@ -89,7 +91,7 @@ describe('JS control flow', () => {
containerRefreshStart(1);
{
if (ctx.condition2) {
let rf2 = embeddedViewStart(2);
let rf2 = embeddedViewStart(2, 1);
{
if (rf2 & RenderFlags.Create) {
text(0, 'Hello');
@ -106,33 +108,45 @@ describe('JS control flow', () => {
}
containerRefreshEnd();
}
}
}, 2);
expect(renderToHtml(Template, ctx)).toEqual('<div><span>Hello</span></div>');
const fixture = new ComponentFixture(App);
fixture.component.condition = true;
fixture.component.condition2 = true;
fixture.update();
expect(fixture.html).toEqual('<div><span>Hello</span></div>');
ctx.condition = false;
expect(renderToHtml(Template, ctx)).toEqual('<div></div>');
fixture.component.condition = false;
fixture.update();
expect(fixture.html).toEqual('<div></div>');
ctx.condition = true;
expect(renderToHtml(Template, ctx)).toEqual('<div><span>Hello</span></div>');
fixture.component.condition = true;
fixture.update();
expect(fixture.html).toEqual('<div><span>Hello</span></div>');
ctx.condition2 = false;
expect(renderToHtml(Template, ctx)).toEqual('<div><span></span></div>');
fixture.component.condition2 = false;
fixture.update();
expect(fixture.html).toEqual('<div><span></span></div>');
ctx.condition2 = true;
expect(renderToHtml(Template, ctx)).toEqual('<div><span>Hello</span></div>');
fixture.component.condition2 = true;
fixture.update();
expect(fixture.html).toEqual('<div><span>Hello</span></div>');
ctx.condition2 = false;
expect(renderToHtml(Template, ctx)).toEqual('<div><span></span></div>');
fixture.component.condition2 = false;
fixture.update();
expect(fixture.html).toEqual('<div><span></span></div>');
ctx.condition = false;
expect(renderToHtml(Template, ctx)).toEqual('<div></div>');
fixture.component.condition = false;
fixture.update();
expect(fixture.html).toEqual('<div></div>');
ctx.condition = true;
expect(renderToHtml(Template, ctx)).toEqual('<div><span></span></div>');
fixture.component.condition = true;
fixture.update();
expect(fixture.html).toEqual('<div><span></span></div>');
ctx.condition2 = true;
expect(renderToHtml(Template, ctx)).toEqual('<div><span>Hello</span></div>');
fixture.component.condition2 = true;
fixture.update();
expect(fixture.html).toEqual('<div><span>Hello</span></div>');
});
it('should work with nested adjacent if blocks', () => {
@ -156,7 +170,7 @@ describe('JS control flow', () => {
containerRefreshStart(0);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 2);
{
if (rf1 & RenderFlags.Create) {
{ container(0); }
@ -166,7 +180,7 @@ describe('JS control flow', () => {
containerRefreshStart(0);
{
if (ctx.condition2) {
let rf2 = embeddedViewStart(2);
let rf2 = embeddedViewStart(2, 1);
{
if (rf2 & RenderFlags.Create) {
text(0, 'Hello');
@ -179,7 +193,7 @@ describe('JS control flow', () => {
containerRefreshStart(1);
{
if (ctx.condition3) {
let rf2 = embeddedViewStart(2);
let rf2 = embeddedViewStart(2, 1);
{
if (rf2 & RenderFlags.Create) {
text(0, 'World');
@ -197,7 +211,7 @@ describe('JS control flow', () => {
containerRefreshEnd();
}
const fixture = new TemplateFixture(createTemplate, updateTemplate);
const fixture = new TemplateFixture(createTemplate, updateTemplate, 1);
expect(fixture.html).toEqual('World');
ctx.condition2 = true;
@ -206,9 +220,6 @@ describe('JS control flow', () => {
});
it('should work with adjacent if blocks managing views in the same container', () => {
const ctx = {condition1: true, condition2: true, condition3: true};
/**
* % if(ctx.condition1) {
* 1
@ -218,28 +229,28 @@ describe('JS control flow', () => {
* 3
* % }
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
container(0);
}
if (rf & RenderFlags.Update) {
containerRefreshStart(0);
if (ctx.condition1) {
const rf1 = embeddedViewStart(1);
const rf1 = embeddedViewStart(1, 1);
if (rf1 & RenderFlags.Create) {
text(0, '1');
}
embeddedViewEnd();
} // can't have ; here due linting rules
if (ctx.condition2) {
const rf2 = embeddedViewStart(2);
const rf2 = embeddedViewStart(2, 1);
if (rf2 & RenderFlags.Create) {
text(0, '2');
}
embeddedViewEnd();
} // can't have ; here due linting rules
if (ctx.condition3) {
const rf3 = embeddedViewStart(3);
const rf3 = embeddedViewStart(3, 1);
if (rf3 & RenderFlags.Create) {
text(0, '3');
}
@ -247,16 +258,22 @@ describe('JS control flow', () => {
}
containerRefreshEnd();
}
}
}, 1);
expect(renderToHtml(Template, ctx)).toEqual('123');
const fixture = new ComponentFixture(App);
fixture.component.condition1 = true;
fixture.component.condition2 = true;
fixture.component.condition3 = true;
fixture.update();
expect(fixture.html).toEqual('123');
ctx.condition2 = false;
expect(renderToHtml(Template, ctx)).toEqual('13');
fixture.component.condition2 = false;
fixture.update();
expect(fixture.html).toEqual('13');
});
it('should work with containers with views as parents', () => {
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{ text(1, 'hello'); }
@ -267,7 +284,7 @@ describe('JS control flow', () => {
containerRefreshStart(2);
{
if (ctx.condition1) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
{
if (rf0 & RenderFlags.Create) {
container(0);
@ -276,7 +293,7 @@ describe('JS control flow', () => {
containerRefreshStart(0);
{
if (ctx.condition2) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
{
if (rf0 & RenderFlags.Create) {
text(0, 'world');
@ -293,19 +310,23 @@ describe('JS control flow', () => {
}
containerRefreshEnd();
}
}
}, 3);
expect(renderToHtml(Template, {condition1: true, condition2: true}))
.toEqual('<div>hello</div>world');
expect(renderToHtml(Template, {condition1: false, condition2: false}))
.toEqual('<div>hello</div>');
const fixture = new ComponentFixture(App);
fixture.component.condition1 = true;
fixture.component.condition2 = true;
fixture.update();
expect(fixture.html).toEqual('<div>hello</div>world');
fixture.component.condition1 = false;
fixture.component.condition2 = false;
fixture.update();
expect(fixture.html).toEqual('<div>hello</div>');
});
it('should work with loop block', () => {
const ctx: {data: string[] | null} = {data: ['a', 'b', 'c']};
function Template(rf: RenderFlags, ctx: any) {
let data: string[] = ['a', 'b', 'c'];
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'ul');
{ container(1); }
@ -314,8 +335,8 @@ describe('JS control flow', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(1);
{
for (let i = 0; i < ctx.data.length; i++) {
let rf1 = embeddedViewStart(1);
for (let i = 0; i < data.length; i++) {
let rf1 = embeddedViewStart(1, 2);
{
if (rf1 & RenderFlags.Create) {
elementStart(0, 'li');
@ -323,7 +344,7 @@ describe('JS control flow', () => {
elementEnd();
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(ctx.data[i]));
textBinding(1, bind(data[i]));
}
}
embeddedViewEnd();
@ -331,31 +352,37 @@ describe('JS control flow', () => {
}
containerRefreshEnd();
}
}
}, 2);
expect(renderToHtml(Template, ctx)).toEqual('<ul><li>a</li><li>b</li><li>c</li></ul>');
const fixture = new ComponentFixture(App);
fixture.update();
expect(fixture.html).toEqual('<ul><li>a</li><li>b</li><li>c</li></ul>');
ctx.data = ['e', 'f'];
expect(renderToHtml(Template, ctx)).toEqual('<ul><li>e</li><li>f</li></ul>');
data = ['e', 'f'];
fixture.update();
expect(fixture.html).toEqual('<ul><li>e</li><li>f</li></ul>');
ctx.data = [];
expect(renderToHtml(Template, ctx)).toEqual('<ul></ul>');
data = [];
fixture.update();
expect(fixture.html).toEqual('<ul></ul>');
ctx.data = ['a', 'b', 'c'];
expect(renderToHtml(Template, ctx)).toEqual('<ul><li>a</li><li>b</li><li>c</li></ul>');
data = ['a', 'b', 'c'];
fixture.update();
expect(fixture.html).toEqual('<ul><li>a</li><li>b</li><li>c</li></ul>');
ctx.data.push('d');
expect(renderToHtml(Template, ctx))
.toEqual('<ul><li>a</li><li>b</li><li>c</li><li>d</li></ul>');
data.push('d');
fixture.update();
expect(fixture.html).toEqual('<ul><li>a</li><li>b</li><li>c</li><li>d</li></ul>');
ctx.data = ['e'];
expect(renderToHtml(Template, ctx)).toEqual('<ul><li>e</li></ul>');
data = ['e'];
fixture.update();
expect(fixture.html).toEqual('<ul><li>e</li></ul>');
});
it('should work with nested loop blocks', () => {
const ctx: {data: string[][] | null} = {data: [['a', 'b', 'c'], ['m', 'n']]};
let data: string[][] = [['a', 'b', 'c'], ['m', 'n']];
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'ul');
{ container(1); }
@ -364,8 +391,8 @@ describe('JS control flow', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(1);
{
for (let i = 0; i < ctx.data[0].length; i++) {
let rf1 = embeddedViewStart(1);
for (let i = 0; i < data[0].length; i++) {
let rf1 = embeddedViewStart(1, 2);
{
if (rf1 & RenderFlags.Create) {
elementStart(0, 'li');
@ -375,13 +402,13 @@ describe('JS control flow', () => {
if (rf1 & RenderFlags.Update) {
containerRefreshStart(1);
{
ctx.data[1].forEach((value: string, ind: number) => {
let rf2 = embeddedViewStart(2);
data[1].forEach((value: string, ind: number) => {
let rf2 = embeddedViewStart(2, 1);
if (rf2 & RenderFlags.Create) {
text(0);
}
if (rf2 & RenderFlags.Update) {
textBinding(0, bind(ctx.data[0][i] + value));
textBinding(0, bind(data[0][i] + value));
}
embeddedViewEnd();
});
@ -394,15 +421,22 @@ describe('JS control flow', () => {
}
containerRefreshEnd();
}
}
}, 2);
expect(renderToHtml(Template, ctx)).toEqual('<ul><li>aman</li><li>bmbn</li><li>cmcn</li></ul>');
const fixture = new ComponentFixture(App);
fixture.update();
expect(fixture.html).toEqual('<ul><li>aman</li><li>bmbn</li><li>cmcn</li></ul>');
ctx.data = [[], []];
expect(renderToHtml(Template, ctx)).toEqual('<ul></ul>');
data = [[], []];
fixture.update();
expect(fixture.html).toEqual('<ul></ul>');
});
it('should work with nested loop blocks where nested container is a root node', () => {
let cafes = [
{name: '1', entrees: ['a', 'b', 'c']}, {name: '2', entrees: ['d', 'e', 'f']},
{name: '3', entrees: ['g', 'h', 'i']}
];
/**
* <div>
@ -417,7 +451,7 @@ describe('JS control flow', () => {
* After
* <div>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{
@ -430,8 +464,8 @@ describe('JS control flow', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(2);
{
for (let i = 0; i < ctx.cafes.length; i++) {
let rf1 = embeddedViewStart(1);
for (let i = 0; i < cafes.length; i++) {
let rf1 = embeddedViewStart(1, 4);
{
if (rf1 & RenderFlags.Create) {
elementStart(0, 'h2');
@ -441,16 +475,16 @@ describe('JS control flow', () => {
text(3, '-');
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(ctx.cafes[i].name));
textBinding(1, bind(cafes[i].name));
containerRefreshStart(2);
{
for (let j = 0; j < ctx.cafes[i].entrees.length; j++) {
let rf2 = embeddedViewStart(2);
for (let j = 0; j < cafes[i].entrees.length; j++) {
let rf2 = embeddedViewStart(2, 1);
if (rf2 & RenderFlags.Create) {
text(0);
}
if (rf2 & RenderFlags.Update) {
textBinding(0, bind(ctx.cafes[i].entrees[j]));
textBinding(0, bind(cafes[i].entrees[j]));
}
embeddedViewEnd();
}
@ -463,30 +497,38 @@ describe('JS control flow', () => {
}
containerRefreshEnd();
}
}
}, 4);
const ctx = {
cafes: [
{name: '1', entrees: ['a', 'b', 'c']}, {name: '2', entrees: ['d', 'e', 'f']},
{name: '3', entrees: ['g', 'h', 'i']}
]
};
expect(renderToHtml(Template, ctx))
const fixture = new ComponentFixture(App);
fixture.update();
expect(fixture.html)
.toEqual('<div>Before<h2>1</h2>abc-<h2>2</h2>def-<h2>3</h2>ghi-After</div>');
ctx.cafes = [];
expect(renderToHtml(Template, ctx)).toEqual('<div>BeforeAfter</div>');
cafes = [];
fixture.update();
expect(fixture.html).toEqual('<div>BeforeAfter</div>');
ctx.cafes = [
cafes = [
{name: '1', entrees: ['a', 'c']},
{name: '2', entrees: ['d', 'e']},
];
expect(renderToHtml(Template, ctx)).toEqual('<div>Before<h2>1</h2>ac-<h2>2</h2>de-After</div>');
fixture.update();
expect(fixture.html).toEqual('<div>Before<h2>1</h2>ac-<h2>2</h2>de-After</div>');
});
it('should work with loop blocks nested three deep', () => {
let cafes = [
{
name: '1',
entrees:
[{name: 'a', foods: [1, 2]}, {name: 'b', foods: [3, 4]}, {name: 'c', foods: [5, 6]}]
},
{
name: '2',
entrees:
[{name: 'd', foods: [1, 2]}, {name: 'e', foods: [3, 4]}, {name: 'f', foods: [5, 6]}]
}
];
/**
* <div>
@ -504,7 +546,7 @@ describe('JS control flow', () => {
* After
* <div>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{
@ -517,8 +559,8 @@ describe('JS control flow', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(2);
{
for (let i = 0; i < ctx.cafes.length; i++) {
let rf1 = embeddedViewStart(1);
for (let i = 0; i < cafes.length; i++) {
let rf1 = embeddedViewStart(1, 4);
{
if (rf1 & RenderFlags.Create) {
elementStart(0, 'h2');
@ -528,11 +570,11 @@ describe('JS control flow', () => {
text(3, '-');
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(ctx.cafes[i].name));
textBinding(1, bind(cafes[i].name));
containerRefreshStart(2);
{
for (let j = 0; j < ctx.cafes[i].entrees.length; j++) {
let rf1 = embeddedViewStart(1);
for (let j = 0; j < cafes[i].entrees.length; j++) {
let rf1 = embeddedViewStart(1, 3);
{
if (rf1 & RenderFlags.Create) {
elementStart(0, 'h3');
@ -541,16 +583,16 @@ describe('JS control flow', () => {
container(2);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(ctx.cafes[i].entrees[j].name));
textBinding(1, bind(cafes[i].entrees[j].name));
containerRefreshStart(2);
{
for (let k = 0; k < ctx.cafes[i].entrees[j].foods.length; k++) {
let rf2 = embeddedViewStart(1);
for (let k = 0; k < cafes[i].entrees[j].foods.length; k++) {
let rf2 = embeddedViewStart(1, 1);
if (rf2 & RenderFlags.Create) {
text(0);
}
if (rf2 & RenderFlags.Update) {
textBinding(0, bind(ctx.cafes[i].entrees[j].foods[k]));
textBinding(0, bind(cafes[i].entrees[j].foods[k]));
}
embeddedViewEnd();
}
@ -569,25 +611,11 @@ describe('JS control flow', () => {
}
containerRefreshEnd();
}
}
}, 4);
const ctx = {
cafes: [
{
name: '1',
entrees:
[{name: 'a', foods: [1, 2]}, {name: 'b', foods: [3, 4]}, {name: 'c', foods: [5, 6]}]
},
{
name: '2',
entrees: [
{name: 'd', foods: [1, 2]}, {name: 'e', foods: [3, 4]}, {name: 'f', foods: [5, 6]}
]
}
]
};
expect(renderToHtml(Template, ctx))
const fixture = new ComponentFixture(App);
fixture.update();
expect(fixture.html)
.toEqual(
'<div>' +
'Before' +
@ -596,14 +624,13 @@ describe('JS control flow', () => {
'After' +
'</div>');
ctx.cafes = [];
expect(renderToHtml(Template, ctx)).toEqual('<div>BeforeAfter</div>');
cafes = [];
fixture.update();
expect(fixture.html).toEqual('<div>BeforeAfter</div>');
});
it('should work with if/else blocks', () => {
const ctx: {message: string | null, condition: boolean} = {message: 'Hello', condition: true};
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{ container(1); }
@ -613,7 +640,7 @@ describe('JS control flow', () => {
containerRefreshStart(1);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 2);
{
if (rf1 & RenderFlags.Create) {
elementStart(0, 'span');
@ -623,7 +650,7 @@ describe('JS control flow', () => {
}
embeddedViewEnd();
} else {
let rf2 = embeddedViewStart(2);
let rf2 = embeddedViewStart(2, 2);
{
if (rf2) {
elementStart(0, 'div');
@ -636,15 +663,20 @@ describe('JS control flow', () => {
}
containerRefreshEnd();
}
}
}, 2);
expect(renderToHtml(Template, ctx)).toEqual('<div><span>Hello</span></div>');
const fixture = new ComponentFixture(App);
fixture.component.condition = true;
fixture.update();
expect(fixture.html).toEqual('<div><span>Hello</span></div>');
ctx.condition = false;
expect(renderToHtml(Template, ctx)).toEqual('<div><div>Goodbye</div></div>');
fixture.component.condition = false;
fixture.update();
expect(fixture.html).toEqual('<div><div>Goodbye</div></div>');
ctx.condition = true;
expect(renderToHtml(Template, ctx)).toEqual('<div><span>Hello</span></div>');
fixture.component.condition = true;
fixture.update();
expect(fixture.html).toEqual('<div><span>Hello</span></div>');
});
it('should work with sibling if blocks with children', () => {
@ -656,6 +688,7 @@ describe('JS control flow', () => {
static ngComponentDef = defineComponent({
type: Comp,
selectors: [['comp']],
consts: 0,
factory: () => {
log.push('comp!');
return new Comp();
@ -672,6 +705,7 @@ describe('JS control flow', () => {
type: App,
selectors: [['app']],
factory: () => new App(),
consts: 3,
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div');
@ -682,7 +716,7 @@ describe('JS control flow', () => {
containerRefreshStart(1);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
element(0, 'comp');
}
@ -693,7 +727,7 @@ describe('JS control flow', () => {
containerRefreshStart(2);
{
if (ctx.condition2) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
element(0, 'comp');
}
@ -720,6 +754,7 @@ describe('JS control flow', () => {
static ngComponentDef = defineComponent({
type: Comp,
selectors: [['comp']],
consts: 0,
factory: () => {
log.push('comp!');
return new Comp();
@ -736,6 +771,7 @@ describe('JS control flow', () => {
type: App,
selectors: [['app']],
factory: () => new App(),
consts: 3,
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div');
@ -746,7 +782,7 @@ describe('JS control flow', () => {
containerRefreshStart(1);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
element(0, 'comp');
}
@ -757,7 +793,7 @@ describe('JS control flow', () => {
containerRefreshStart(2);
{
if (ctx.condition2) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
element(0, 'comp');
}
@ -782,8 +818,7 @@ describe('JS control flow', () => {
describe('JS for loop', () => {
it('should work with sibling for blocks', () => {
const ctx: {data1: string[] | null,
data2: number[] | null} = {data1: ['a', 'b', 'c'], data2: [1, 2]};
const config: {data1: string[], data2: number[]} = {data1: ['a', 'b', 'c'], data2: [1, 2]};
/**
* <div>
@ -794,7 +829,7 @@ describe('JS for loop', () => {
* % }
* </div>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{ container(1); }
@ -803,47 +838,51 @@ describe('JS for loop', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(1);
{
for (let i = 0; i < ctx.data1.length; i++) {
let rf2 = embeddedViewStart(1);
for (let i = 0; i < config.data1.length; i++) {
let rf2 = embeddedViewStart(1, 1);
if (rf2 & RenderFlags.Create) {
text(0);
}
if (rf2 & RenderFlags.Update) {
textBinding(0, bind(ctx.data1[i]));
textBinding(0, bind(config.data1[i]));
}
embeddedViewEnd();
}
for (let j = 0; j < ctx.data2.length; j++) {
let rf2 = embeddedViewStart(1);
for (let j = 0; j < config.data2.length; j++) {
let rf2 = embeddedViewStart(1, 1);
if (rf2 & RenderFlags.Create) {
text(0);
}
if (rf2 & RenderFlags.Update) {
textBinding(0, bind(ctx.data2[j]));
textBinding(0, bind(config.data2[j]));
}
embeddedViewEnd();
}
}
containerRefreshEnd();
}
}
}, 2);
expect(renderToHtml(Template, ctx)).toEqual('<div>abc12</div>');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<div>abc12</div>');
ctx.data1 = ['e', 'f'];
expect(renderToHtml(Template, ctx)).toEqual('<div>ef12</div>');
config.data1 = ['e', 'f'];
fixture.update();
expect(fixture.html).toEqual('<div>ef12</div>');
ctx.data2 = [8];
expect(renderToHtml(Template, ctx)).toEqual('<div>ef8</div>');
config.data2 = [8];
fixture.update();
expect(fixture.html).toEqual('<div>ef8</div>');
ctx.data1 = ['x', 'y'];
expect(renderToHtml(Template, ctx)).toEqual('<div>xy8</div>');
config.data1 = ['x', 'y'];
fixture.update();
expect(fixture.html).toEqual('<div>xy8</div>');
});
});
describe('function calls', () => {
it('should work', () => {
const ctx: {data: string[]} = {data: ['foo', 'bar']};
let data: string[] = ['foo', 'bar'];
function spanify(rf: RenderFlags, ctx: {message: string | null}) {
const message = ctx.message;
@ -857,7 +896,7 @@ describe('function calls', () => {
}
}
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{
@ -871,26 +910,27 @@ describe('function calls', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(2);
{
let rf0 = embeddedViewStart(0);
{ spanify(rf0, {message: ctx.data[0]}); }
let rf0 = embeddedViewStart(0, 2);
{ spanify(rf0, {message: data[0]}); }
embeddedViewEnd();
}
containerRefreshEnd();
containerRefreshStart(3);
{
let rf0 = embeddedViewStart(0);
{ spanify(rf0, {message: ctx.data[1]}); }
let rf0 = embeddedViewStart(0, 2);
{ spanify(rf0, {message: data[1]}); }
embeddedViewEnd();
}
containerRefreshEnd();
}
}
}, 5);
expect(renderToHtml(Template, ctx))
.toEqual('<div>Before<span>foo</span><span>bar</span>After</div>');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<div>Before<span>foo</span><span>bar</span>After</div>');
ctx.data = [];
expect(renderToHtml(Template, ctx)).toEqual('<div>Before<span></span><span></span>After</div>');
data = [];
fixture.update();
expect(fixture.html).toEqual('<div>Before<span></span><span></span>After</div>');
});
});

View File

@ -34,7 +34,7 @@ describe('di', () => {
}
/** <div dir #dir="dir"> {{ dir.value }} </div> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', ''], ['dir', 'dir']);
{ text(2); }
@ -44,9 +44,10 @@ describe('di', () => {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
}
}
}, 3, [Directive]);
expect(renderToHtml(Template, {}, [Directive])).toEqual('<div dir="">Created</div>');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<div dir="">Created</div>');
});
});
@ -94,7 +95,7 @@ describe('di', () => {
* <span dirB dirC #dir="dirC"> {{ dir.value }} </span>
* </div>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dirA', '']);
{
@ -108,11 +109,10 @@ describe('di', () => {
const tmp = reference(2) as any;
textBinding(3, bind(tmp.value));
}
}
}, 4, [DirA, DirB, DirC]);
const defs = [DirA, DirB, DirC];
expect(renderToHtml(Template, {}, defs))
.toEqual('<div dira=""><span dirb="" dirc="">DirADirB</span></div>');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<div dira=""><span dirb="" dirc="">DirADirB</span></div>');
});
it('should instantiate injected directives in dependency order', () => {
@ -131,7 +131,7 @@ describe('di', () => {
if (rf & RenderFlags.Create) {
element(0, 'div', ['dirA', '', 'dirB', '']);
}
}, [DirA, DirB]);
}, 1, [DirA, DirB]);
new ComponentFixture(App);
expect(log).toEqual(['DirB', 'DirA (dep: DirB)']);
@ -157,7 +157,7 @@ describe('di', () => {
element(0, 'div', ['dirB', '']);
element(1, 'div', ['dirA', '']);
}
}, [DirA, DirB]);
}, 2, [DirA, DirB]);
const fakeModuleInjector: any = {
get: function(token: any) {
@ -177,6 +177,7 @@ describe('di', () => {
static ngComponentDef = defineComponent({
selectors: [['comp']],
type: Comp,
consts: 0,
factory: () => new Comp(directiveInject(DirB)),
template: (ctx: any, fm: boolean) => {}
});
@ -187,7 +188,7 @@ describe('di', () => {
if (rf & RenderFlags.Create) {
element(0, 'comp', ['dirB', '']);
}
}, [Comp, DirB]);
}, 1, [Comp, DirB]);
new ComponentFixture(App);
expect(log).toEqual(['DirB', 'Comp (dep: DirB)']);
@ -216,14 +217,14 @@ describe('di', () => {
containerRefreshStart(0);
{
for (let i = 0; i < 3; i++) {
if (embeddedViewStart(0)) {
if (embeddedViewStart(0, 1)) {
element(0, 'div', ['dirA', '', 'dirB', '']);
}
embeddedViewEnd();
}
}
containerRefreshEnd();
}, [DirA, DirB]);
}, 1, [DirA, DirB]);
new ComponentFixture(App);
expect(log).toEqual(
@ -272,7 +273,7 @@ describe('di', () => {
if (rf & RenderFlags.Create) {
element(0, 'div', ['dirA', '', 'dirB', '', 'dirC', '']);
}
}, [DirA, DirB, DirC]);
}, 1, [DirA, DirB, DirC]);
new ComponentFixture(App);
expect(log).toEqual(['DirA', 'DirC', 'DirB (deps: DirA and DirC)']);
@ -285,6 +286,7 @@ describe('di', () => {
static ngComponentDef = defineComponent({
selectors: [['comp']],
type: Comp,
consts: 0,
factory: () => new Comp(directiveInject(DirD)),
template: (ctx: any, fm: boolean) => {}
});
@ -331,7 +333,7 @@ describe('di', () => {
if (rf & RenderFlags.Create) {
element(0, 'comp', ['dirA', '', 'dirB', '', 'dirC', '', 'dirD', '']);
}
}, [Comp, DirA, DirB, DirC, DirD]);
}, 1, [Comp, DirA, DirB, DirC, DirD]);
new ComponentFixture(App);
expect(log).toEqual(
@ -358,6 +360,7 @@ describe('di', () => {
selectors: [['app']],
type: App,
factory: () => new App(),
consts: 1,
/** <div dirA dirB dirC></div> */
template: (rf: RenderFlags, ctx: any) => {
if (rf & RenderFlags.Create) {
@ -407,14 +410,14 @@ describe('di', () => {
if (rf & RenderFlags.Create) {
element(0, 'div', ['dirA', '', 'dirB', '']);
}
}, [DirA, DirB]);
}, 1, [DirA, DirB]);
/** <parent dirB></parent> */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'parent', ['dirB', '']);
}
}, [Parent, DirB]);
}, 1, [Parent, DirB]);
new ComponentFixture(App);
expect(log).toEqual(['DirB', 'DirB', 'DirA (dep: DirB - 2)']);
@ -432,6 +435,7 @@ describe('di', () => {
static ngComponentDef = defineComponent({
type: MyComponent,
selectors: [['my-component']],
consts: 1,
factory: () => new MyComponent(directiveInject(MyService)),
template: function(rf: RenderFlags, ctx: MyComponent) {
if (rf & RenderFlags.Create) {
@ -475,7 +479,7 @@ describe('di', () => {
if (rf & RenderFlags.Create) {
element(0, 'div', ['dir', '']);
}
}, [Dir, OtherDir]);
}, 1, [Dir, OtherDir]);
expect(() => new ComponentFixture(App)).toThrowError(/Injector: NOT_FOUND \[OtherDir\]/);
});
@ -510,7 +514,7 @@ describe('di', () => {
element(0, 'div', ['other', '']);
element(1, 'div', ['dir', '']);
}
}, [Dir, OtherDir]);
}, 2, [Dir, OtherDir]);
expect(() => new ComponentFixture(App)).toThrowError(/Injector: NOT_FOUND \[OtherDir\]/);
});
@ -544,7 +548,7 @@ describe('di', () => {
if (rf & RenderFlags.Create) {
element(0, 'div', ['dirA', '', 'dirB', '']);
}
}, [DirA, DirB]);
}, 1, [DirA, DirB]);
expect(() => new ComponentFixture(App)).toThrowError(/Cannot instantiate cyclic dependency!/);
});
@ -566,7 +570,7 @@ describe('di', () => {
if (rf & RenderFlags.Create) {
element(0, 'div', ['dir', '']);
}
}, [Dir]);
}, 1, [Dir]);
expect(() => new ComponentFixture(App)).toThrowError(/Cannot instantiate cyclic dependency!/);
});
@ -604,7 +608,7 @@ describe('di', () => {
if (rf & RenderFlags.Create) {
element(0, 'div', ['dirA', '']);
}
}, [DirA, DirB]);
}, 1, [DirA, DirB]);
expect(() => {
new ComponentFixture(App);
@ -634,7 +638,7 @@ describe('di', () => {
element(0, 'div', ['dirB', '']);
element(1, 'div', ['dirA', '']);
}
}, [DirA, DirB]);
}, 2, [DirA, DirB]);
expect(() => {
new ComponentFixture(App);
@ -660,14 +664,14 @@ describe('di', () => {
if (rf & RenderFlags.Create) {
element(0, 'div', ['dirA', '', 'dirB', 'self']);
}
}, [DirA, DirB]);
}, 1, [DirA, DirB]);
/* <comp dirB="parent"></comp> */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'comp', ['dirB', 'parent']);
}
}, [Comp, DirB]);
}, 1, [Comp, DirB]);
new ComponentFixture(App);
expect(dirA !.dirB.value).toEqual('parent');
@ -697,7 +701,7 @@ describe('di', () => {
element(1, 'div', ['dirA', '']);
elementEnd();
}
}, [DirA, DirB]);
}, 2, [DirA, DirB]);
expect(() => { new ComponentFixture(App); }).toThrowError(/Injector: NOT_FOUND \[DirB\]/);
});
@ -728,7 +732,7 @@ describe('di', () => {
element(1, 'div', ['dirA', '', 'dirC', '']);
elementEnd();
}
}, [DirA, DirB, DirC]);
}, 2, [DirA, DirB, DirC]);
expect(() => {
(DirA as any)['__NG_ELEMENT_ID__'] = 1;
@ -755,14 +759,14 @@ describe('di', () => {
if (rf & RenderFlags.Create) {
element(0, 'div', ['dirA', '']);
}
}, [DirA, DirB]);
}, 1, [DirA, DirB]);
/* <comp dirB></comp> */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'comp', ['dirB', '']);
}
}, [Comp, DirB]);
}, 1, [Comp, DirB]);
expect(() => { new ComponentFixture(App); }).toThrowError(/Injector: NOT_FOUND \[DirB\]/);
@ -806,7 +810,7 @@ describe('di', () => {
* {{ dir.value }} - {{ dirSame.value }}
* </div>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dirSame', 'dirSame', 'dir', 'dir']);
{ text(3); }
@ -818,11 +822,10 @@ describe('di', () => {
const tmp2 = reference(2) as any;
textBinding(3, interpolation2('', tmp2.value, '-', tmp1.value, ''));
}
}
}, 4, [Directive, DirectiveSameInstance]);
const defs = [Directive, DirectiveSameInstance];
expect(renderToHtml(Template, {}, defs))
.toEqual('<div dir="" dirsame="">ElementRef-true</div>');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<div dir="" dirsame="">ElementRef-true</div>');
});
});
@ -860,10 +863,10 @@ describe('di', () => {
* {{ dir.value }} - {{ dirSame.value }}
* </ng-template>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(0, function() {
}, undefined, ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']);
}, 0, undefined, ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']);
text(3);
}
if (rf & RenderFlags.Update) {
@ -871,10 +874,10 @@ describe('di', () => {
const tmp2 = reference(2) as any;
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.value, ''));
}
}
}, 4, [Directive, DirectiveSameInstance]);
const defs = [Directive, DirectiveSameInstance];
expect(renderToHtml(Template, {}, defs)).toEqual('TemplateRef-true');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('TemplateRef-true');
});
});
@ -913,7 +916,7 @@ describe('di', () => {
* {{ dir.value }} - {{ dirSame.value }}
* </div>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']);
{ text(3); }
@ -924,11 +927,10 @@ describe('di', () => {
const tmp2 = reference(2) as any;
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.value, ''));
}
}
}, 4, [Directive, DirectiveSameInstance]);
const defs = [Directive, DirectiveSameInstance];
expect(renderToHtml(Template, {}, defs))
.toEqual('<div dir="" dirsame="">ViewContainerRef-true</div>');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<div dir="" dirsame="">ViewContainerRef-true</div>');
});
});
@ -944,6 +946,7 @@ describe('di', () => {
type: MyComp,
selectors: [['my-comp']],
factory: () => comp = new MyComp(injectChangeDetectorRef()),
consts: 1,
template: function(rf: RenderFlags, ctx: MyComp) {
if (rf & RenderFlags.Create) {
projectionDef();
@ -1012,7 +1015,7 @@ describe('di', () => {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
}
}, directives);
}, 3, directives);
const app = renderComponent(MyApp);
// ChangeDetectorRef is the token, ViewRef has historically been the constructor
@ -1031,6 +1034,7 @@ describe('di', () => {
static ngComponentDef = defineComponent({
type: MyApp,
selectors: [['my-app']],
consts: 3,
factory: () => new MyApp(injectChangeDetectorRef()),
/** <div dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */
template: function(rf: RenderFlags, ctx: any) {
@ -1063,6 +1067,7 @@ describe('di', () => {
static ngComponentDef = defineComponent({
type: MyApp,
selectors: [['my-app']],
consts: 4,
factory: () => new MyApp(injectChangeDetectorRef()),
/**
* <my-comp>
@ -1105,6 +1110,7 @@ describe('di', () => {
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(injectChangeDetectorRef()),
consts: 1,
/**
* % if (showing) {
* <div dir dirSameInstance #dir="dir"> {{ dir.value }} </div>
@ -1118,7 +1124,7 @@ describe('di', () => {
containerRefreshStart(0);
{
if (ctx.showing) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 3);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
{ text(2); }
@ -1147,6 +1153,18 @@ describe('di', () => {
});
it('should inject host component ChangeDetectorRef into directives on containers', () => {
function C1(rf1: RenderFlags, ctx1: any) {
if (rf1 & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
{ text(2); }
elementEnd();
}
if (rf1 & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
}
}
class MyApp {
showing = true;
@ -1156,27 +1174,16 @@ describe('di', () => {
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(injectChangeDetectorRef()),
consts: 1,
/** <div *myIf="showing" dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */
template: function(rf: RenderFlags, ctx: MyApp) {
if (rf & RenderFlags.Create) {
template(0, C1, null, ['myIf', 'showing']);
template(0, C1, 3, null, ['myIf', 'showing']);
}
if (rf & RenderFlags.Update) {
containerRefreshStart(0);
containerRefreshEnd();
}
function C1(rf1: RenderFlags, ctx1: any) {
if (rf1 & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
{ text(2); }
elementEnd();
}
if (rf1 & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
}
}
},
directives: directives
});
@ -1221,7 +1228,7 @@ describe('di', () => {
exist = injectAttribute('exist');
nonExist = injectAttribute('nonExist');
}
});
}, 1);
new ComponentFixture(MyApp);
expect(exist).toEqual('existValue');
@ -1240,7 +1247,7 @@ describe('di', () => {
exist = injectAttribute('exist');
nonExist = injectAttribute('nonExist');
}
});
}, 1);
new ComponentFixture(MyApp);
expect(exist).toEqual('existValue');
@ -1353,7 +1360,7 @@ describe('di', () => {
* </span>
* </div>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['parentDir', '']);
{ container(1); }
@ -1362,7 +1369,7 @@ describe('di', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(1);
{
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 4);
if (rf1 & RenderFlags.Create) {
elementStart(
0, 'span', ['childDir', '', 'child2Dir', ''],
@ -1379,10 +1386,10 @@ describe('di', () => {
}
containerRefreshEnd();
}
}
}, 2, [ChildDirective, Child2Directive, ParentDirective]);
const defs = [ChildDirective, Child2Directive, ParentDirective];
expect(renderToHtml(Template, {}, defs))
const fixture = new ComponentFixture(App);
expect(fixture.html)
.toEqual('<div parentdir=""><span child2dir="" childdir="">Directive-true</span></div>');
});
@ -1394,7 +1401,7 @@ describe('di', () => {
describe('getOrCreateNodeInjector', () => {
it('should handle initial undefined state', () => {
const contentView = createLViewData(
null !, createTView(-1, null, null, null, null), null, LViewFlags.CheckAlways);
null !, createTView(-1, null, 0, null, null, null), null, LViewFlags.CheckAlways);
const oldView = enterView(contentView, null !);
try {
const parent = createLNode(0, TNodeType.Element, null, null, null, null);

View File

@ -35,7 +35,7 @@ describe('directive', () => {
function Template() { element(0, 'span', [AttributeMarker.SelectOnly, 'dir']); }
const fixture = new TemplateFixture(Template, () => {}, [Directive]);
const fixture = new TemplateFixture(Template, () => {}, 1, [Directive]);
expect(fixture.html).toEqual('<span class="foo"></span>');
directiveInstance !.klass = 'bar';
@ -86,7 +86,7 @@ describe('directive', () => {
function updateTemplate() { elementProperty(0, 'test', bind(false)); }
const fixture = new TemplateFixture(createTemplate, updateTemplate, [Directive]);
const fixture = new TemplateFixture(createTemplate, updateTemplate, 1, [Directive]);
// the "test" attribute should not be reflected in the DOM as it is here only for directive
// matching purposes
@ -142,7 +142,7 @@ describe('directive', () => {
elementProperty(0, 'prop2', bind(true));
}
const fixture = new TemplateFixture(createTemplate, updateTemplate, [Directive]);
const fixture = new TemplateFixture(createTemplate, updateTemplate, 1, [Directive]);
// the "test" attribute should not be reflected in the DOM as it is here only for directive
// matching purposes
@ -173,7 +173,7 @@ describe('directive', () => {
elementEnd();
}
const fixture = new TemplateFixture(createTemplate, () => {}, [Directive]);
const fixture = new TemplateFixture(createTemplate, () => {}, 1, [Directive]);
// "out" should not be part of reflected attributes
expect(fixture.html).toEqual('<span></span>');

View File

@ -17,7 +17,7 @@ describe('exports', () => {
it('should support export of DOM element', () => {
/** <input value="one" #myInput> {{ myInput.value }} */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'input', ['value', 'one'], ['myInput', '']);
text(2);
@ -26,15 +26,27 @@ describe('exports', () => {
const tmp = reference(1) as any;
textBinding(2, tmp.value);
}
}
}, 3);
expect(renderToHtml(Template, {})).toEqual('<input value="one">one');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<input value="one">one');
});
it('should support basic export of component', () => {
class MyComponent {
name = 'Nancy';
static ngComponentDef = defineComponent({
type: MyComponent,
selectors: [['comp']],
consts: 0,
template: function() {},
factory: () => new MyComponent
});
}
/** <comp #myComp></comp> {{ myComp.name }} */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'comp', null, ['myComp', '']);
text(2);
@ -43,20 +55,10 @@ describe('exports', () => {
const tmp = reference(1) as any;
textBinding(2, tmp.name);
}
}
}, 3, [MyComponent]);
class MyComponent {
name = 'Nancy';
static ngComponentDef = defineComponent({
type: MyComponent,
selectors: [['comp']],
template: function() {},
factory: () => new MyComponent
});
}
expect(renderToHtml(Template, {}, [MyComponent])).toEqual('<comp></comp>Nancy');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<comp></comp>Nancy');
});
it('should support component instance fed into directive', () => {
@ -68,6 +70,7 @@ describe('exports', () => {
static ngComponentDef = defineComponent({
type: MyComponent,
selectors: [['comp']],
consts: 0,
template: function() {},
factory: () => new MyComponent
});
@ -88,7 +91,7 @@ describe('exports', () => {
const defs = [MyComponent, MyDir];
/** <comp #myComp></comp> <div [myDir]="myComp"></div> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'comp', null, ['myComp', '']);
element(2, 'div', ['myDir', '']);
@ -97,26 +100,13 @@ describe('exports', () => {
const tmp = reference(1) as any;
elementProperty(2, 'myDir', bind(tmp));
}
}
}, 3, defs);
renderToHtml(Template, {}, defs);
const fixture = new ComponentFixture(App);
expect(myDir !.myDir).toEqual(myComponent !);
});
it('should work with directives with exportAs set', () => {
/** <div someDir #myDir="someDir"></div> {{ myDir.name }} */
function Template(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', ['someDir', ''], ['myDir', 'someDir']);
text(2);
}
if (rf & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, tmp.name);
}
}
class SomeDir {
name = 'Drew';
static ngDirectiveDef = defineDirective({
@ -127,7 +117,20 @@ describe('exports', () => {
});
}
expect(renderToHtml(Template, {}, [SomeDir])).toEqual('<div somedir=""></div>Drew');
/** <div someDir #myDir="someDir"></div> {{ myDir.name }} */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', ['someDir', ''], ['myDir', 'someDir']);
text(2);
}
if (rf & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, tmp.name);
}
}, 3, [SomeDir]);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<div somedir=""></div>Drew');
});
it('should throw if export name is not found', () => {
@ -137,7 +140,7 @@ describe('exports', () => {
if (rf & RenderFlags.Create) {
element(0, 'div', null, ['myDir', 'someDir']);
}
});
}, 1);
expect(() => {
const fixture = new ComponentFixture(App);
@ -147,7 +150,7 @@ describe('exports', () => {
describe('forward refs', () => {
it('should work with basic text bindings', () => {
/** {{ myInput.value}} <input value="one" #myInput> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
text(0);
element(1, 'input', ['value', 'one'], ['myInput', '']);
@ -156,15 +159,16 @@ describe('exports', () => {
const tmp = reference(2) as any;
textBinding(0, bind(tmp.value));
}
}
}, 3);
expect(renderToHtml(Template, {})).toEqual('one<input value="one">');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('one<input value="one">');
});
it('should work with element properties', () => {
/** <div [title]="myInput.value"</div> <input value="one" #myInput> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div');
element(1, 'input', ['value', 'one'], ['myInput', '']);
@ -173,14 +177,15 @@ describe('exports', () => {
const tmp = reference(2) as any;
elementProperty(0, 'title', bind(tmp.value));
}
}
}, 3);
expect(renderToHtml(Template, {})).toEqual('<div title="one"></div><input value="one">');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<div title="one"></div><input value="one">');
});
it('should work with element attrs', () => {
/** <div [attr.aria-label]="myInput.value"</div> <input value="one" #myInput> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div');
element(1, 'input', ['value', 'one'], ['myInput', '']);
@ -189,14 +194,15 @@ describe('exports', () => {
const tmp = reference(2) as any;
elementAttribute(0, 'aria-label', bind(tmp.value));
}
}
}, 3);
expect(renderToHtml(Template, {})).toEqual('<div aria-label="one"></div><input value="one">');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<div aria-label="one"></div><input value="one">');
});
it('should work with element classes', () => {
/** <div [class.red]="myInput.checked"</div> <input type="checkbox" checked #myInput> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
elementStyling([InitialStylingFlags.VALUES_MODE, 'red', true]);
@ -208,10 +214,10 @@ describe('exports', () => {
elementClassProp(0, 0, tmp.checked);
elementStylingApply(0);
}
}
}, 3);
expect(renderToHtml(Template, {}))
.toEqual('<div class="red"></div><input checked="true" type="checkbox">');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<div class="red"></div><input checked="true" type="checkbox">');
});
it('should work with component refs', () => {
@ -225,6 +231,7 @@ describe('exports', () => {
static ngComponentDef = defineComponent({
type: MyComponent,
selectors: [['comp']],
consts: 0,
template: function(rf: RenderFlags, ctx: MyComponent) {},
factory: () => new MyComponent
});
@ -245,7 +252,7 @@ describe('exports', () => {
}
/** <div [myDir]="myComp"></div><comp #myComp></comp> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', ['myDir', '']);
element(1, 'comp', null, ['myComp', '']);
@ -254,16 +261,32 @@ describe('exports', () => {
const tmp = reference(2) as any;
elementProperty(0, 'myDir', bind(tmp));
}
}
}, 3, [MyComponent, MyDir]);
renderToHtml(Template, {}, [MyComponent, MyDir]);
const fixture = new ComponentFixture(App);
expect(myDir !.myDir).toEqual(myComponent !);
});
it('should work with multiple forward refs', () => {
let myComponent: MyComponent;
class MyComponent {
name = 'Nancy';
constructor() { myComponent = this; }
static ngComponentDef = defineComponent({
type: MyComponent,
selectors: [['comp']],
consts: 0,
template: function() {},
factory: () => new MyComponent
});
}
/** {{ myInput.value }} {{ myComp.name }} <comp #myComp></comp> <input value="one" #myInput>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
text(0);
text(1);
@ -276,28 +299,14 @@ describe('exports', () => {
textBinding(0, bind(tmp2.value));
textBinding(1, bind(tmp1.name));
}
}
}, 6, [MyComponent]);
let myComponent: MyComponent;
class MyComponent {
name = 'Nancy';
constructor() { myComponent = this; }
static ngComponentDef = defineComponent({
type: MyComponent,
selectors: [['comp']],
template: function() {},
factory: () => new MyComponent
});
}
expect(renderToHtml(Template, {}, [MyComponent]))
.toEqual('oneNancy<comp></comp><input value="one">');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('oneNancy<comp></comp><input value="one">');
});
it('should work inside a view container', () => {
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
{ container(1); }
@ -307,7 +316,7 @@ describe('exports', () => {
containerRefreshStart(1);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 2);
{
if (rf1 & RenderFlags.Create) {
text(0);
@ -323,12 +332,16 @@ describe('exports', () => {
}
containerRefreshEnd();
}
}
}, 2);
expect(renderToHtml(Template, {
condition: true
})).toEqual('<div>one<input value="one"></div>');
expect(renderToHtml(Template, {condition: false})).toEqual('<div></div>');
const fixture = new ComponentFixture(App);
fixture.component.condition = true;
fixture.update();
expect(fixture.html).toEqual('<div>one<input value="one"></div>');
fixture.component.condition = false;
fixture.update();
expect(fixture.html).toEqual('<div></div>');
});
it('should support local refs in nested dynamic views', () => {
@ -348,12 +361,12 @@ describe('exports', () => {
if (rf & RenderFlags.Create) {
elementStart(0, 'input', ['value', 'one'], ['outerInput', '']);
elementEnd();
template(2, outerTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']);
template(2, outerTemplate, 5, '', [AttributeMarker.SelectOnly, 'ngIf']);
}
if (rf & RenderFlags.Update) {
elementProperty(2, 'ngIf', bind(app.outer));
}
}, [NgIf]);
}, 3, [NgIf]);
function outerTemplate(rf: RenderFlags, outer: any) {
if (rf & RenderFlags.Create) {
@ -362,7 +375,7 @@ describe('exports', () => {
text(1);
elementStart(2, 'input', ['value', 'two'], ['innerInput', '']);
elementEnd();
template(4, innerTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']);
template(4, innerTemplate, 2, '', [AttributeMarker.SelectOnly, 'ngIf']);
}
elementEnd();
}

View File

@ -10,7 +10,7 @@ import {NgForOfContext} from '@angular/common';
import {Component} from '../../src/core';
import {defineComponent} from '../../src/render3/definition';
import {I18nExpInstruction, I18nInstruction, i18nApply, i18nExpMapping, i18nInterpolation1, i18nInterpolation2, i18nInterpolation3, i18nInterpolation4, i18nInterpolation5, i18nInterpolation6, i18nInterpolation7, i18nInterpolation8, i18nInterpolationV, i18nMapping} from '../../src/render3/i18n';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, projection, projectionDef, template, text, textBinding} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, nextContext, projection, projectionDef, template, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {NgForOf} from './common_with_def';
import {ComponentFixture, TemplateFixture} from './render_util';
@ -60,7 +60,7 @@ describe('Runtime i18n', () => {
i18nApply(1, i18n_1[0]);
}
const fixture = new TemplateFixture(createTemplate);
const fixture = new TemplateFixture(createTemplate, () => {}, 5);
expect(fixture.html).toEqual('<div><c>trad 1</c><a>trad 2<b>trad 3</b></a></div>');
});
@ -76,6 +76,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 3,
// Initial template:
// <div i18n>
// {{exp1}} {{exp2}}
@ -134,6 +135,7 @@ describe('Runtime i18n', () => {
static ngComponentDef = defineComponent({
type: MyApp,
factory: () => new MyApp(),
consts: 2,
selectors: [['my-app']],
// Initial template:
// <div i18n>
@ -191,6 +193,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 1,
// Initial template:
// <div i18n i18n-title title="{{exp1}}{{exp2}}"></div>
@ -236,6 +239,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 8,
// Initial template:
// <div i18n i18n-title title="{{exp1}}{{exp2}}">
// {{exp1}}
@ -332,6 +336,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 6,
// Initial template:
// <div>
// <a i18n>
@ -426,6 +431,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 3,
// Initial template:
// before (
// % if (condition) { // with i18n
@ -452,7 +458,7 @@ describe('Runtime i18n', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(1);
{
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
// Start of translated section 1
text(0); // EXP_1
@ -523,7 +529,7 @@ describe('Runtime i18n', () => {
i18nApply(2, i18n_1[0]);
}
const fixture = new TemplateFixture(createTemplate);
const fixture = new TemplateFixture(createTemplate, () => {}, 5);
expect(fixture.html).toEqual('<div><a></a><b></b><d></d></div>');
});
@ -531,6 +537,22 @@ describe('Runtime i18n', () => {
const MSG_DIV_SECTION_1 = `{$START_LI}valeur: {$EXP_1}!{$END_LI}`;
// The indexes are based on each template function
let i18n_1: I18nInstruction[][];
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 2
elementStart(0, 'li'); // START_LI
{ text(1); } // EXP_1
elementEnd();
// End of translated section 2
i18nApply(0, i18n_1[1]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
class MyApp {
items: string[] = ['1', '2'];
@ -538,6 +560,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 2,
// Initial template:
// <ul i18n>
// <li *ngFor="let item of items">value: {{item}}</li>
@ -558,7 +581,7 @@ describe('Runtime i18n', () => {
elementStart(0, 'ul');
{
// Start of translated section 1
template(1, liTemplate, null, ['ngForOf', '']); // START_LI
template(1, liTemplate, 2, null, ['ngForOf', '']); // START_LI
// End of translated section 1
}
elementEnd();
@ -567,21 +590,6 @@ describe('Runtime i18n', () => {
if (rf & RenderFlags.Update) {
elementProperty(1, 'ngForOf', bind(myApp.items));
}
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 2
elementStart(0, 'li'); // START_LI
{ text(1); } // EXP_1
elementEnd();
// End of translated section 2
i18nApply(0, i18n_1[1]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
},
directives: () => [NgForOf]
});
@ -615,6 +623,37 @@ describe('Runtime i18n', () => {
`{$START_LI_0}valeur: {$EXP_1}!{$END_LI_0}{$START_LI_1}valeur bis: {$EXP_2}!{$END_LI_1}`;
// The indexes are based on each template function
let i18n_1: I18nInstruction[][];
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 2
elementStart(0, 'li'); // START_LI_0
{ text(1); } // EXP_1
elementEnd();
// End of translated section 2
i18nApply(0, i18n_1[1]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
function liTemplateBis(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 3
elementStart(0, 'li'); // START_LI_1
{ text(1); } // EXP_2
elementEnd();
// End of translated section 3
i18nApply(0, i18n_1[2]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
class MyApp {
items: string[] = ['1', '2'];
@ -622,6 +661,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 3,
// Initial template:
// <ul i18n>
// <li *ngFor="let item of items">value: {{item}}</li>
@ -645,8 +685,8 @@ describe('Runtime i18n', () => {
elementStart(0, 'ul');
{
// Start of translated section 1
template(1, liTemplate, null, ['ngForOf', '']); // START_LI_0
template(2, liTemplateBis, null, ['ngForOf', '']); // START_LI_1
template(1, liTemplate, 2, null, ['ngForOf', '']); // START_LI_0
template(2, liTemplateBis, 2, null, ['ngForOf', '']); // START_LI_1
// End of translated section 1
}
elementEnd();
@ -656,36 +696,6 @@ describe('Runtime i18n', () => {
elementProperty(1, 'ngForOf', bind(myApp.items));
elementProperty(2, 'ngForOf', bind(myApp.items));
}
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 2
elementStart(0, 'li'); // START_LI_0
{ text(1); } // EXP_1
elementEnd();
// End of translated section 2
i18nApply(0, i18n_1[1]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
function liTemplateBis(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 3
elementStart(0, 'li'); // START_LI_1
{ text(1); } // EXP_2
elementEnd();
// End of translated section 3
i18nApply(0, i18n_1[2]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
},
directives: () => [NgForOf]
});
@ -725,6 +735,37 @@ describe('Runtime i18n', () => {
`{$START_LI_1}valeur bis: {$EXP_2}!{$END_LI_1}{$START_LI_0}valeur: {$EXP_1}!{$END_LI_0}`;
// The indexes are based on each template function
let i18n_1: I18nInstruction[][];
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 2
elementStart(0, 'li'); // START_LI_0
{ text(1); } // EXP_1
elementEnd();
// End of translated section 2
i18nApply(0, i18n_1[1]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
function liTemplateBis(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 3
elementStart(0, 'li'); // START_LI_1
{ text(1); } // EXP_2
elementEnd();
// End of translated section 3
i18nApply(0, i18n_1[2]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
class MyApp {
items: string[] = ['1', '2'];
@ -732,6 +773,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 3,
// Initial template:
// <ul i18n>
// <li *ngFor="let item of items">value: {{item}}</li>
@ -755,8 +797,8 @@ describe('Runtime i18n', () => {
elementStart(0, 'ul');
{
// Start of translated section 1
template(1, liTemplate, null, ['ngForOf', '']); // START_LI_0
template(2, liTemplateBis, null, ['ngForOf', '']); // START_LI_1
template(1, liTemplate, 2, null, ['ngForOf', '']); // START_LI_0
template(2, liTemplateBis, 2, null, ['ngForOf', '']); // START_LI_1
// End of translated section 1
}
elementEnd();
@ -766,36 +808,6 @@ describe('Runtime i18n', () => {
elementProperty(1, 'ngForOf', bind(myApp.items));
elementProperty(2, 'ngForOf', bind(myApp.items));
}
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 2
elementStart(0, 'li'); // START_LI_0
{ text(1); } // EXP_1
elementEnd();
// End of translated section 2
i18nApply(0, i18n_1[1]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
function liTemplateBis(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 3
elementStart(0, 'li'); // START_LI_1
{ text(1); } // EXP_2
elementEnd();
// End of translated section 3
i18nApply(0, i18n_1[2]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
},
directives: () => [NgForOf]
});
@ -834,6 +846,40 @@ describe('Runtime i18n', () => {
const MSG_DIV_SECTION_1 = `{$START_LI}{$START_SPAN}valeur: {$EXP_1}!{$END_SPAN}{$END_LI}`;
// The indexes are based on each template function
let i18n_1: I18nInstruction[][];
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 2
elementStart(0, 'li'); // START_LI
{
template(1, spanTemplate, 2, null, ['ngForOf', '']); // START_SPAN
}
elementEnd();
// End of translated section 2
i18nApply(0, i18n_1[1]);
}
if (rf1 & RenderFlags.Update) {
const myApp = nextContext();
elementProperty(1, 'ngForOf', bind(myApp.items));
}
}
function spanTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 3
elementStart(0, 'span'); // START_SPAN
{ text(1); } // EXP_1
elementEnd();
// End of translated section 3
i18nApply(0, i18n_1[2]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
class MyApp {
items: string[] = ['1', '2'];
@ -841,6 +887,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 2,
// Initial template:
// <ul i18n>
// <li *ngFor="let item of items">
@ -866,7 +913,7 @@ describe('Runtime i18n', () => {
elementStart(0, 'ul');
{
// Start of translated section 1
template(1, liTemplate, null, ['ngForOf', '']); // START_LI
template(1, liTemplate, 2, null, ['ngForOf', '']); // START_LI
// End of translated section 1
}
elementEnd();
@ -875,38 +922,6 @@ describe('Runtime i18n', () => {
if (rf & RenderFlags.Update) {
elementProperty(1, 'ngForOf', bind(myApp.items));
}
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 2
elementStart(0, 'li'); // START_LI
{
template(1, spanTemplate, null, ['ngForOf', '']); // START_SPAN
}
elementEnd();
// End of translated section 2
i18nApply(0, i18n_1[1]);
}
if (rf1 & RenderFlags.Update) {
elementProperty(1, 'ngForOf', bind(myApp.items));
}
}
function spanTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 3
elementStart(0, 'span'); // START_SPAN
{ text(1); } // EXP_1
elementEnd();
// End of translated section 3
i18nApply(0, i18n_1[2]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
},
directives: () => [NgForOf]
});
@ -947,6 +962,21 @@ describe('Runtime i18n', () => {
// The indexes are based on each template function
let i18n_1: I18nInstruction[][];
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 2
elementStart(0, 'li'); // START_LI_1
{ text(1); } // EXP_1
elementEnd();
// End of translated section 2
i18nApply(0, i18n_1[1]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
class MyApp {
items: string[] = ['first', 'second'];
@ -954,6 +984,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 5,
// Initial template:
// <ul i18n>
// <li>start</li>
@ -979,9 +1010,9 @@ describe('Runtime i18n', () => {
elementStart(0, 'ul');
{
// Start of translated section 1
element(1, 'li'); // START_LI_0
template(2, liTemplate, null, ['ngForOf', '']); // START_LI_1
elementStart(3, 'li'); // START_LI_2
element(1, 'li'); // START_LI_0
template(2, liTemplate, 2, null, ['ngForOf', '']); // START_LI_1
elementStart(3, 'li'); // START_LI_2
{ text(4, 'delete me'); }
elementEnd();
// End of translated section 1
@ -992,21 +1023,6 @@ describe('Runtime i18n', () => {
if (rf & RenderFlags.Update) {
elementProperty(2, 'ngForOf', bind(myApp.items));
}
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 2
elementStart(0, 'li'); // START_LI_1
{ text(1); } // EXP_1
elementEnd();
// End of translated section 2
i18nApply(0, i18n_1[1]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
},
directives: () => [NgForOf]
});
@ -1042,6 +1058,20 @@ describe('Runtime i18n', () => {
const MSG_DIV_SECTION_1 = `loop`;
// The indexes are based on each template function
let i18n_1: I18nInstruction[][];
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 2
elementStart(0, 'li'); // START_LI
{ text(1); } // EXP_1
elementEnd();
// End of translated section 2
i18nApply(0, i18n_1[1]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
class MyApp {
items: string[] = ['first', 'second'];
@ -1050,6 +1080,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 2,
// Initial template:
// <ul i18n>
// <li *ngFor="let item of items">value: {{item}}</li>
@ -1070,7 +1101,7 @@ describe('Runtime i18n', () => {
elementStart(0, 'ul');
{
// Start of translated section 1
template(1, liTemplate, undefined, ['ngForOf', '']); // START_LI
template(1, liTemplate, 2, undefined, ['ngForOf', '']); // START_LI
// End of translated section 1
}
elementEnd();
@ -1079,21 +1110,6 @@ describe('Runtime i18n', () => {
if (rf & RenderFlags.Update) {
elementProperty(1, 'ngForOf', bind(myApp.items));
}
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
// This is a container so the whole template is a translated section
// Start of translated section 2
elementStart(0, 'li'); // START_LI
{ text(1); } // EXP_1
elementEnd();
// End of translated section 2
i18nApply(0, i18n_1[1]);
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
}
},
directives: () => [NgForOf]
});
@ -1131,6 +1147,7 @@ describe('Runtime i18n', () => {
type: Child,
selectors: [['child']],
factory: () => new Child(),
consts: 2,
template: (rf: RenderFlags, cmp: Child) => {
if (rf & RenderFlags.Create) {
projectionDef();
@ -1169,6 +1186,7 @@ describe('Runtime i18n', () => {
selectors: [['parent']],
directives: [Child],
factory: () => new Parent(),
consts: 4,
template: (rf: RenderFlags, cmp: Parent) => {
if (rf & RenderFlags.Create) {
if (!i18n_1) {
@ -1227,6 +1245,7 @@ describe('Runtime i18n', () => {
type: Child,
selectors: [['child']],
factory: () => new Child(),
consts: 2,
template: (rf: RenderFlags, cmp: Child) => {
if (rf & RenderFlags.Create) {
projectionDef();
@ -1265,6 +1284,7 @@ describe('Runtime i18n', () => {
selectors: [['parent']],
directives: [Child],
factory: () => new Parent(),
consts: 6,
template: (rf: RenderFlags, cmp: Parent) => {
if (rf & RenderFlags.Create) {
if (!i18n_1) {
@ -1314,6 +1334,7 @@ describe('Runtime i18n', () => {
type: GrandChild,
selectors: [['grand-child']],
factory: () => new GrandChild(),
consts: 2,
template: (rf: RenderFlags, cmp: Child) => {
if (rf & RenderFlags.Create) {
projectionDef();
@ -1333,6 +1354,7 @@ describe('Runtime i18n', () => {
selectors: [['child']],
directives: [GrandChild],
factory: () => new Child(),
consts: 2,
template: (rf: RenderFlags, cmp: Child) => {
if (rf & RenderFlags.Create) {
projectionDef();
@ -1360,6 +1382,7 @@ describe('Runtime i18n', () => {
selectors: [['parent']],
directives: [Child],
factory: () => new Parent(),
consts: 2,
template: (rf: RenderFlags, cmp: Parent) => {
if (rf & RenderFlags.Create) {
if (!i18n_1) {
@ -1396,6 +1419,7 @@ describe('Runtime i18n', () => {
type: Child,
selectors: [['child']],
factory: () => new Child(),
consts: 1,
template: (rf: RenderFlags, cmp: Child) => {
if (rf & RenderFlags.Create) {
projectionDef([[['span']]], ['span']);
@ -1425,6 +1449,7 @@ describe('Runtime i18n', () => {
selectors: [['parent']],
directives: [Child],
factory: () => new Parent(),
consts: 3,
template: (rf: RenderFlags, cmp: Parent) => {
if (rf & RenderFlags.Create) {
if (!i18n_1) {
@ -1465,6 +1490,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 1,
// Initial template:
// <div i18n i18n-title title="{{exp1}}{{exp2}}"></div>
@ -1501,6 +1527,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 1,
// Initial template:
// <div i18n i18n-title title="{{exp1}}{{exp2}}{{exp3}}"></div>
@ -1536,6 +1563,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 1,
// Initial template:
// <div i18n i18n-title title="{{exp1}}{{exp2}}{{exp3}}{{exp4}}"></div>
@ -1573,6 +1601,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 1,
// Initial template:
// <div i18n i18n-title title="{{exp1}}{{exp2}}{{exp3}}{{exp4}}{{exp5}}"></div>
@ -1615,6 +1644,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 1,
// Initial template:
// <div i18n i18n-title title="{{exp1}}{{exp2}}{{exp3}}{{exp4}}{{exp5}}{{exp6}}"></div>
@ -1659,6 +1689,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 1,
// Initial template:
// <div i18n i18n-title
// title="{{exp1}}{{exp2}}{{exp3}}{{exp4}}{{exp5}}{{exp6}}{{exp7}}"></div>
@ -1712,6 +1743,7 @@ describe('Runtime i18n', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 1,
// Initial template:
// <div i18n i18n-title
// title="{{exp1}}{{exp2}}{{exp3}}{{exp4}}{{exp5}}{{exp6}}{{exp7}}{{exp8}}"></div>

View File

@ -40,7 +40,7 @@ describe('instructions', () => {
describe('bind', () => {
it('should update bindings when value changes', () => {
const t = new TemplateFixture(createAnchor);
const t = new TemplateFixture(createAnchor, () => {}, 1);
t.update(() => elementProperty(0, 'title', bind('Hello')));
expect(t.html).toEqual('<a title="Hello"></a>');
@ -58,7 +58,7 @@ describe('instructions', () => {
it('should not update bindings when value does not change', () => {
const idempotentUpdate = () => elementProperty(0, 'title', bind('Hello'));
const t = new TemplateFixture(createAnchor, idempotentUpdate);
const t = new TemplateFixture(createAnchor, idempotentUpdate, 1);
t.update();
expect(t.html).toEqual('<a title="Hello"></a>');
@ -77,7 +77,9 @@ describe('instructions', () => {
describe('element', () => {
it('should create an element', () => {
const t = new TemplateFixture(() => { element(0, 'div', ['id', 'test', 'title', 'Hello']); });
const t = new TemplateFixture(() => {
element(0, 'div', ['id', 'test', 'title', 'Hello']);
}, () => {}, 1);
const div = (t.hostNode.native as HTMLElement).querySelector('div') !;
expect(div.id).toEqual('test');
@ -105,7 +107,7 @@ describe('instructions', () => {
'title',
'Hello',
]);
});
}, () => {}, 1);
const div = (t.hostNode.native as HTMLElement).querySelector('div') !;
const attrs: any = div.attributes;
@ -134,7 +136,7 @@ describe('instructions', () => {
describe('elementAttribute', () => {
it('should use sanitizer function', () => {
const t = new TemplateFixture(createDiv);
const t = new TemplateFixture(createDiv, () => {}, 1);
t.update(() => elementAttribute(0, 'title', 'javascript:true', sanitizeUrl));
expect(t.html).toEqual('<div title="unsafe:javascript:true"></div>');
@ -155,7 +157,7 @@ describe('instructions', () => {
describe('elementProperty', () => {
it('should use sanitizer function when available', () => {
const t = new TemplateFixture(createDiv);
const t = new TemplateFixture(createDiv, () => {}, 1);
t.update(() => elementProperty(0, 'title', 'javascript:true', sanitizeUrl));
expect(t.html).toEqual('<div title="unsafe:javascript:true"></div>');
@ -173,7 +175,7 @@ describe('instructions', () => {
});
it('should not stringify non string values', () => {
const t = new TemplateFixture(createDiv);
const t = new TemplateFixture(createDiv, () => {}, 1);
t.update(() => elementProperty(0, 'hidden', false));
// The hidden property would be true if `false` was stringified into `"false"`.
@ -191,7 +193,7 @@ describe('instructions', () => {
describe('elementStyleProp', () => {
it('should automatically sanitize unless a bypass operation is applied', () => {
const t = new TemplateFixture(
() => { return createDiv(['background-image'], defaultStyleSanitizer); });
() => { return createDiv(['background-image'], defaultStyleSanitizer); }, () => {}, 1);
t.update(() => {
elementStyleProp(0, 0, 'url("http://server")');
elementStylingApply(0);
@ -210,7 +212,7 @@ describe('instructions', () => {
it('should not re-apply the style value even if it is a newly bypassed again', () => {
const sanitizerInterceptor = new MockSanitizerInterceptor();
const t = createTemplateFixtureWithSanitizer(
() => createDiv(['background-image'], sanitizerInterceptor.getStyleSanitizer()),
() => createDiv(['background-image'], sanitizerInterceptor.getStyleSanitizer()), 1,
sanitizerInterceptor);
t.update(() => {
@ -237,7 +239,7 @@ describe('instructions', () => {
}
it('should add style', () => {
const fixture = new TemplateFixture(createDivWithStyle);
const fixture = new TemplateFixture(createDivWithStyle, () => {}, 1);
fixture.update(() => {
elementStylingMap(0, null, {'background-color': 'red'});
elementStylingApply(0);
@ -250,7 +252,7 @@ describe('instructions', () => {
const sanitizerInterceptor =
new MockSanitizerInterceptor(value => { detectedValues.push(value); });
const fixture = createTemplateFixtureWithSanitizer(
() => createDiv([], sanitizerInterceptor.getStyleSanitizer()), sanitizerInterceptor);
() => createDiv([], sanitizerInterceptor.getStyleSanitizer()), 1, sanitizerInterceptor);
fixture.update(() => {
elementStylingMap(0, null, {
@ -280,7 +282,7 @@ describe('instructions', () => {
}
it('should add class', () => {
const fixture = new TemplateFixture(createDivWithStyling);
const fixture = new TemplateFixture(createDivWithStyling, () => {}, 1);
fixture.update(() => {
elementStylingMap(0, 'multiple classes');
elementStylingApply(0);
@ -292,6 +294,32 @@ describe('instructions', () => {
describe('performance counters', () => {
it('should create tViews only once for each nested level', () => {
const _c0 = ['ngFor', '', 'ngForOf', ''];
function ToDoAppComponent_NgForOf_Template_0(rf: RenderFlags, ctx0: NgForOfContext<any>) {
if (rf & RenderFlags.Create) {
elementStart(0, 'ul');
template(1, ToDoAppComponent_NgForOf_NgForOf_Template_1, 2, null, _c0);
elementEnd();
}
if (rf & RenderFlags.Update) {
const row_r2 = ctx0.$implicit;
elementProperty(1, 'ngForOf', bind(row_r2));
}
}
function ToDoAppComponent_NgForOf_NgForOf_Template_1(
rf: RenderFlags, ctx1: NgForOfContext<any>) {
if (rf & RenderFlags.Create) {
elementStart(0, 'li');
text(1);
elementEnd();
}
if (rf & RenderFlags.Update) {
const col_r3 = ctx1.$implicit;
textBinding(1, interpolation1('', col_r3, ''));
}
}
/**
* <ul *ngFor="let row of rows">
* <li *ngFor="let col of row.cols">{{col}}</li>
@ -304,37 +332,14 @@ describe('instructions', () => {
type: NestedLoops,
selectors: [['nested-loops']],
factory: function ToDoAppComponent_Factory() { return new NestedLoops(); },
consts: 1,
template: function ToDoAppComponent_Template(rf: RenderFlags, ctx: NestedLoops) {
if (rf & RenderFlags.Create) {
template(0, ToDoAppComponent_NgForOf_Template_0, null, _c0);
template(0, ToDoAppComponent_NgForOf_Template_0, 2, null, _c0);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'ngForOf', bind(ctx.rows));
}
function ToDoAppComponent_NgForOf_Template_0(
rf: RenderFlags, ctx0: NgForOfContext<any>) {
if (rf & RenderFlags.Create) {
elementStart(0, 'ul');
template(1, ToDoAppComponent_NgForOf_NgForOf_Template_1, null, _c0);
elementEnd();
}
if (rf & RenderFlags.Update) {
const row_r2 = ctx0.$implicit;
elementProperty(1, 'ngForOf', bind(row_r2));
}
function ToDoAppComponent_NgForOf_NgForOf_Template_1(
rf: RenderFlags, ctx1: NgForOfContext<any>) {
if (rf & RenderFlags.Create) {
elementStart(0, 'li');
text(1);
elementEnd();
}
if (rf & RenderFlags.Update) {
const col_r3 = ctx1.$implicit;
textBinding(1, interpolation1('', col_r3, ''));
}
}
}
},
directives: [NgForOf]
});
@ -351,7 +356,7 @@ describe('instructions', () => {
describe('sanitization injection compatibility', () => {
it('should work for url sanitization', () => {
const s = new LocalMockSanitizer(value => `${value}-sanitized`);
const t = new TemplateFixture(createAnchor, undefined, null, null, s);
const t = new TemplateFixture(createAnchor, undefined, 1, null, null, s);
const inputValue = 'http://foo';
const outputValue = 'http://foo-sanitized';
@ -362,7 +367,7 @@ describe('instructions', () => {
it('should bypass url sanitization if marked by the service', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createAnchor, undefined, null, null, s);
const t = new TemplateFixture(createAnchor, undefined, 1, null, null, s);
const inputValue = s.bypassSecurityTrustUrl('http://foo');
const outputValue = 'http://foo';
@ -373,7 +378,7 @@ describe('instructions', () => {
it('should bypass ivy-level url sanitization if a custom sanitizer is used', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createAnchor, undefined, null, null, s);
const t = new TemplateFixture(createAnchor, undefined, 1, null, null, s);
const inputValue = bypassSanitizationTrustUrl('http://foo');
const outputValue = 'http://foo-ivy';
@ -384,7 +389,7 @@ describe('instructions', () => {
it('should work for style sanitization', () => {
const s = new LocalMockSanitizer(value => `color:blue`);
const t = new TemplateFixture(createDiv, undefined, null, null, s);
const t = new TemplateFixture(createDiv, undefined, 1, null, null, s);
const inputValue = 'color:red';
const outputValue = 'color:blue';
@ -395,7 +400,7 @@ describe('instructions', () => {
it('should bypass style sanitization if marked by the service', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createDiv, undefined, null, null, s);
const t = new TemplateFixture(createDiv, undefined, 1, null, null, s);
const inputValue = s.bypassSecurityTrustStyle('color:maroon');
const outputValue = 'color:maroon';
@ -406,7 +411,7 @@ describe('instructions', () => {
it('should bypass ivy-level style sanitization if a custom sanitizer is used', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createDiv, undefined, null, null, s);
const t = new TemplateFixture(createDiv, undefined, 1, null, null, s);
const inputValue = bypassSanitizationTrustStyle('font-family:foo');
const outputValue = 'font-family:foo-ivy';
@ -417,7 +422,7 @@ describe('instructions', () => {
it('should work for resourceUrl sanitization', () => {
const s = new LocalMockSanitizer(value => `${value}-sanitized`);
const t = new TemplateFixture(createScript, undefined, null, null, s);
const t = new TemplateFixture(createScript, undefined, 1, null, null, s);
const inputValue = 'http://resource';
const outputValue = 'http://resource-sanitized';
@ -428,7 +433,7 @@ describe('instructions', () => {
it('should bypass resourceUrl sanitization if marked by the service', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createScript, undefined, null, null, s);
const t = new TemplateFixture(createScript, undefined, 1, null, null, s);
const inputValue = s.bypassSecurityTrustResourceUrl('file://all-my-secrets.pdf');
const outputValue = 'file://all-my-secrets.pdf';
@ -439,7 +444,7 @@ describe('instructions', () => {
it('should bypass ivy-level resourceUrl sanitization if a custom sanitizer is used', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createScript, undefined, null, null, s);
const t = new TemplateFixture(createScript, undefined, 1, null, null, s);
const inputValue = bypassSanitizationTrustResourceUrl('file://all-my-secrets.pdf');
const outputValue = 'file://all-my-secrets.pdf-ivy';
@ -450,7 +455,7 @@ describe('instructions', () => {
it('should work for script sanitization', () => {
const s = new LocalMockSanitizer(value => `${value} //sanitized`);
const t = new TemplateFixture(createScript, undefined, null, null, s);
const t = new TemplateFixture(createScript, undefined, 1, null, null, s);
const inputValue = 'fn();';
const outputValue = 'fn(); //sanitized';
@ -461,7 +466,7 @@ describe('instructions', () => {
it('should bypass script sanitization if marked by the service', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createScript, undefined, null, null, s);
const t = new TemplateFixture(createScript, undefined, 1, null, null, s);
const inputValue = s.bypassSecurityTrustScript('alert("bar")');
const outputValue = 'alert("bar")';
@ -472,7 +477,7 @@ describe('instructions', () => {
it('should bypass ivy-level script sanitization if a custom sanitizer is used', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createScript, undefined, null, null, s);
const t = new TemplateFixture(createScript, undefined, 1, null, null, s);
const inputValue = bypassSanitizationTrustScript('alert("bar")');
const outputValue = 'alert("bar")-ivy';
@ -483,7 +488,7 @@ describe('instructions', () => {
it('should work for html sanitization', () => {
const s = new LocalMockSanitizer(value => `${value} <!--sanitized-->`);
const t = new TemplateFixture(createDiv, undefined, null, null, s);
const t = new TemplateFixture(createDiv, undefined, 1, null, null, s);
const inputValue = '<header></header>';
const outputValue = '<header></header> <!--sanitized-->';
@ -494,7 +499,7 @@ describe('instructions', () => {
it('should bypass html sanitization if marked by the service', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createDiv, undefined, null, null, s);
const t = new TemplateFixture(createDiv, undefined, 1, null, null, s);
const inputValue = s.bypassSecurityTrustHtml('<div onclick="alert(123)"></div>');
const outputValue = '<div onclick="alert(123)"></div>';
@ -505,7 +510,7 @@ describe('instructions', () => {
it('should bypass ivy-level script sanitization if a custom sanitizer is used', () => {
const s = new LocalMockSanitizer(value => '');
const t = new TemplateFixture(createDiv, undefined, null, null, s);
const t = new TemplateFixture(createDiv, undefined, 1, null, null, s);
const inputValue = bypassSanitizationTrustHtml('<div onclick="alert(123)"></div>');
const outputValue = '<div onclick="alert(123)"></div>-ivy';
@ -568,6 +573,7 @@ function stripStyleWsCharacters(value: string): string {
return value.replace(/;/g, '').replace(/:\s+/g, ':');
}
function createTemplateFixtureWithSanitizer(buildFn: () => any, sanitizer: Sanitizer) {
return new TemplateFixture(buildFn, () => {}, null, null, sanitizer);
function createTemplateFixtureWithSanitizer(
buildFn: () => any, consts: number, sanitizer: Sanitizer) {
return new TemplateFixture(buildFn, () => {}, consts, null, null, sanitizer);
}

View File

@ -25,7 +25,7 @@ describe('render3 integration test', () => {
describe('render', () => {
it('should render basic template', () => {
expect(renderToHtml(Template, {})).toEqual('<span title="Hello">Greetings</span>');
expect(renderToHtml(Template, {}, 2)).toEqual('<span title="Hello">Greetings</span>');
function Template(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
@ -43,19 +43,25 @@ describe('render3 integration test', () => {
});
it('should render and update basic "Hello, World" template', () => {
expect(renderToHtml(Template, 'World')).toEqual('<h1>Hello, World!</h1>');
expect(renderToHtml(Template, 'New World')).toEqual('<h1>Hello, New World!</h1>');
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'h1');
{ text(1); }
elementEnd();
}
if (rf & RenderFlags.Update) {
textBinding(1, interpolation1('Hello, ', ctx, '!'));
textBinding(1, interpolation1('Hello, ', ctx.name, '!'));
}
}
}, 2);
const fixture = new ComponentFixture(App);
fixture.component.name = 'World';
fixture.update();
expect(fixture.html).toEqual('<h1>Hello, World!</h1>');
fixture.component.name = 'New World';
fixture.update();
expect(fixture.html).toEqual('<h1>Hello, New World!</h1>');
});
});
@ -70,8 +76,8 @@ describe('render3 integration test', () => {
}
}
expect(renderToHtml(Template, 'benoit')).toEqual('benoit');
expect(renderToHtml(Template, undefined)).toEqual('');
expect(renderToHtml(Template, 'benoit', 1)).toEqual('benoit');
expect(renderToHtml(Template, undefined, 1)).toEqual('');
expect(ngDevMode).toHaveProperties({
firstTemplatePass: 0,
tNode: 2,
@ -90,8 +96,8 @@ describe('render3 integration test', () => {
}
}
expect(renderToHtml(Template, 'benoit')).toEqual('benoit');
expect(renderToHtml(Template, null)).toEqual('');
expect(renderToHtml(Template, 'benoit', 1)).toEqual('benoit');
expect(renderToHtml(Template, null, 1)).toEqual('');
expect(ngDevMode).toHaveProperties({
firstTemplatePass: 0,
tNode: 2,
@ -109,8 +115,8 @@ describe('render3 integration test', () => {
textBinding(0, rf & RenderFlags.Create ? value : NO_CHANGE);
}
}
expect(renderToHtml(Template, 'once')).toEqual('once');
expect(renderToHtml(Template, 'twice')).toEqual('once');
expect(renderToHtml(Template, 'once', 1)).toEqual('once');
expect(renderToHtml(Template, 'twice', 1)).toEqual('once');
expect(ngDevMode).toHaveProperties({
firstTemplatePass: 0,
tNode: 2,
@ -123,22 +129,29 @@ describe('render3 integration test', () => {
describe('Siblings update', () => {
it('should handle a flat list of static/bound text nodes', () => {
function Template(rf: RenderFlags, name: string) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
text(0, 'Hello ');
text(1);
text(2, '!');
}
if (rf & RenderFlags.Update) {
textBinding(1, bind(name));
textBinding(1, bind(ctx.name));
}
}
expect(renderToHtml(Template, 'world')).toEqual('Hello world!');
expect(renderToHtml(Template, 'monde')).toEqual('Hello monde!');
}, 3);
const fixture = new ComponentFixture(App);
fixture.component.name = 'world';
fixture.update();
expect(fixture.html).toEqual('Hello world!');
fixture.component.name = 'monde';
fixture.update();
expect(fixture.html).toEqual('Hello monde!');
});
it('should handle a list of static/bound text nodes as element children', () => {
function Template(rf: RenderFlags, name: string) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'b');
{
@ -149,15 +162,22 @@ describe('render3 integration test', () => {
elementEnd();
}
if (rf & RenderFlags.Update) {
textBinding(2, bind(name));
textBinding(2, bind(ctx.name));
}
}
expect(renderToHtml(Template, 'world')).toEqual('<b>Hello world!</b>');
expect(renderToHtml(Template, 'mundo')).toEqual('<b>Hello mundo!</b>');
}, 4);
const fixture = new ComponentFixture(App);
fixture.component.name = 'world';
fixture.update();
expect(fixture.html).toEqual('<b>Hello world!</b>');
fixture.component.name = 'mundo';
fixture.update();
expect(fixture.html).toEqual('<b>Hello mundo!</b>');
});
it('should render/update text node as a child of a deep list of elements', () => {
function Template(rf: RenderFlags, name: string) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'b');
{
@ -176,15 +196,22 @@ describe('render3 integration test', () => {
elementEnd();
}
if (rf & RenderFlags.Update) {
textBinding(4, interpolation1('Hello ', name, '!'));
textBinding(4, interpolation1('Hello ', ctx.name, '!'));
}
}
expect(renderToHtml(Template, 'world')).toEqual('<b><b><b><b>Hello world!</b></b></b></b>');
expect(renderToHtml(Template, 'mundo')).toEqual('<b><b><b><b>Hello mundo!</b></b></b></b>');
}, 5);
const fixture = new ComponentFixture(App);
fixture.component.name = 'world';
fixture.update();
expect(fixture.html).toEqual('<b><b><b><b>Hello world!</b></b></b></b>');
fixture.component.name = 'mundo';
fixture.update();
expect(fixture.html).toEqual('<b><b><b><b>Hello mundo!</b></b></b></b>');
});
it('should update 2 sibling elements', () => {
function Template(rf: RenderFlags, id: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'b');
{
@ -196,26 +223,32 @@ describe('render3 integration test', () => {
elementEnd();
}
if (rf & RenderFlags.Update) {
elementAttribute(2, 'id', bind(id));
elementAttribute(2, 'id', bind(ctx.id));
}
}
expect(renderToHtml(Template, 'foo'))
.toEqual('<b><span></span><span class="foo" id="foo"></span></b>');
expect(renderToHtml(Template, 'bar'))
.toEqual('<b><span></span><span class="foo" id="bar"></span></b>');
}, 3);
const fixture = new ComponentFixture(App);
fixture.component.id = 'foo';
fixture.update();
expect(fixture.html).toEqual('<b><span></span><span class="foo" id="foo"></span></b>');
fixture.component.id = 'bar';
fixture.update();
expect(fixture.html).toEqual('<b><span></span><span class="foo" id="bar"></span></b>');
});
it('should handle sibling text node after element with child text node', () => {
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'p');
{ text(1, 'hello'); }
elementEnd();
text(2, 'world');
}
}
}, 3);
expect(renderToHtml(Template, null)).toEqual('<p>hello</p>world');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<p>hello</p>world');
});
});
@ -227,6 +260,7 @@ describe('render3 integration test', () => {
static ngComponentDef = defineComponent({
type: TodoComponent,
selectors: [['todo']],
consts: 3,
template: function TodoTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'p');
@ -247,23 +281,26 @@ describe('render3 integration test', () => {
const defs = [TodoComponent];
it('should support a basic component template', () => {
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'todo');
}
}
}, 1, defs);
expect(renderToHtml(Template, null, defs)).toEqual('<todo><p>Todo one</p></todo>');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<todo><p>Todo one</p></todo>');
});
it('should support a component template with sibling', () => {
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'todo');
text(1, 'two');
}
}
expect(renderToHtml(Template, null, defs)).toEqual('<todo><p>Todo one</p></todo>two');
}, 2, defs);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<todo><p>Todo one</p></todo>two');
});
it('should support a component template with component sibling', () => {
@ -271,14 +308,15 @@ describe('render3 integration test', () => {
* <todo></todo>
* <todo></todo>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'todo');
element(1, 'todo');
}
}
expect(renderToHtml(Template, null, defs))
.toEqual('<todo><p>Todo one</p></todo><todo><p>Todo one</p></todo>');
}, 2, defs);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<todo><p>Todo one</p></todo><todo><p>Todo one</p></todo>');
});
it('should support a component with binding on host element', () => {
@ -289,6 +327,7 @@ describe('render3 integration test', () => {
static ngComponentDef = defineComponent({
type: TodoComponentHostBinding,
selectors: [['todo']],
consts: 1,
template: function TodoComponentHostBindingTemplate(
rf: RenderFlags, ctx: TodoComponentHostBinding) {
if (rf & RenderFlags.Create) {
@ -308,16 +347,18 @@ describe('render3 integration test', () => {
});
}
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'todo');
}
}
}, 1, [TodoComponentHostBinding]);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<todo title="one">one</todo>');
const defs = [TodoComponentHostBinding];
expect(renderToHtml(Template, {}, defs)).toEqual('<todo title="one">one</todo>');
cmptInstance !.title = 'two';
expect(renderToHtml(Template, {}, defs)).toEqual('<todo title="two">two</todo>');
fixture.update();
expect(fixture.html).toEqual('<todo title="two">two</todo>');
});
it('should support root component with host attribute', () => {
@ -326,6 +367,7 @@ describe('render3 integration test', () => {
type: HostAttributeComp,
selectors: [['host-attr-comp']],
factory: () => new HostAttributeComp(),
consts: 0,
template: (rf: RenderFlags, ctx: HostAttributeComp) => {},
attributes: ['role', 'button']
});
@ -342,6 +384,7 @@ describe('render3 integration test', () => {
static ngComponentDef = defineComponent({
type: MyComp,
selectors: [['comp']],
consts: 2,
template: function MyCompTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'p');
@ -356,13 +399,14 @@ describe('render3 integration test', () => {
});
}
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'comp');
}
}
}, 1, [MyComp]);
expect(renderToHtml(Template, null, [MyComp])).toEqual('<comp><p>Bess</p></comp>');
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<comp><p>Bess</p></comp>');
});
it('should support a component with sub-views', () => {
@ -377,6 +421,7 @@ describe('render3 integration test', () => {
static ngComponentDef = defineComponent({
type: MyComp,
selectors: [['comp']],
consts: 1,
template: function MyCompTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
container(0);
@ -385,7 +430,7 @@ describe('render3 integration test', () => {
containerRefreshStart(0);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 2);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'div');
{ text(1, 'text'); }
@ -403,20 +448,23 @@ describe('render3 integration test', () => {
}
/** <comp [condition]="condition"></comp> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'comp');
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'condition', bind(ctx.condition));
}
}
}, 1, [MyComp]);
const defs = [MyComp];
expect(renderToHtml(Template, {condition: true}, defs))
.toEqual('<comp><div>text</div></comp>');
expect(renderToHtml(Template, {condition: false}, defs)).toEqual('<comp></comp>');
const fixture = new ComponentFixture(App);
fixture.component.condition = true;
fixture.update();
expect(fixture.html).toEqual('<comp><div>text</div></comp>');
fixture.component.condition = false;
fixture.update();
expect(fixture.html).toEqual('<comp></comp>');
});
});
@ -424,7 +472,6 @@ describe('render3 integration test', () => {
describe('ng-container', () => {
it('should insert as a child of a regular element', () => {
/**
* <div>before|<ng-container>Greetings<span></span></ng-container>|after</div>
*/
@ -443,7 +490,7 @@ describe('render3 integration test', () => {
elementEnd();
}
const fixture = new TemplateFixture(Template);
const fixture = new TemplateFixture(Template, () => {}, 6);
expect(fixture.html).toEqual('<div>before|Greetings<span></span>|after</div>');
});
@ -462,7 +509,7 @@ describe('render3 integration test', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(0);
if (ctx.value) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 3);
{
if (rf1 & RenderFlags.Create) {
elementStart(0, 'div');
@ -478,7 +525,7 @@ describe('render3 integration test', () => {
}
containerRefreshEnd();
}
});
}, 1);
const fixture = new ComponentFixture(TestCmpt);
expect(fixture.html).toEqual('');
@ -507,7 +554,7 @@ describe('render3 integration test', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(0);
if (ctx.value) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 2);
{
if (rf1 & RenderFlags.Create) {
elementContainerStart(0);
@ -519,7 +566,7 @@ describe('render3 integration test', () => {
}
containerRefreshEnd();
}
});
}, 1);
const fixture = new ComponentFixture(TestCmpt);
expect(fixture.html).toEqual('');
@ -558,12 +605,12 @@ describe('render3 integration test', () => {
const TestCmpt =
createComponent('test-cmpt', function(rf: RenderFlags, ctx: {value: any}) {
if (rf & RenderFlags.Create) {
template(0, ngIfTemplate, null, [AttributeMarker.SelectOnly, 'ngIf']);
template(0, ngIfTemplate, 2, null, [AttributeMarker.SelectOnly, 'ngIf']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'ngIf', bind(ctx.value));
}
}, [NgIf]);
}, 1, [NgIf]);
const fixture = new ComponentFixture(TestCmpt);
expect(fixture.html).toEqual('');
@ -614,12 +661,12 @@ describe('render3 integration test', () => {
</ng-template>`;
const TestCmpt = createComponent('test-cmpt', function(rf: RenderFlags) {
if (rf & RenderFlags.Create) {
template(0, embeddedTemplate, null, [AttributeMarker.SelectOnly, 'testDirective']);
template(0, embeddedTemplate, 2, null, [AttributeMarker.SelectOnly, 'testDirective']);
}
if (rf & RenderFlags.Update) {
testDirective = loadDirective<TestDirective>(0);
}
}, [TestDirective]);
}, 1, [TestDirective]);
const fixture = new ComponentFixture(TestCmpt);
expect(fixture.html).toEqual('');
@ -643,11 +690,11 @@ describe('render3 integration test', () => {
{ text(1, 'component template'); }
elementContainerEnd();
}
});
}, 2);
function App() { element(0, 'test-cmpt'); }
const fixture = new TemplateFixture(App, () => {}, [TestCmpt]);
const fixture = new TemplateFixture(App, () => {}, 1, [TestCmpt]);
expect(fixture.html).toEqual('<test-cmpt>component template</test-cmpt>');
});
@ -675,11 +722,11 @@ describe('render3 integration test', () => {
}
elementContainerEnd();
}
});
}, 4);
function App() { element(0, 'test-cmpt'); }
const fixture = new TemplateFixture(App, () => {}, [TestCmpt]);
const fixture = new TemplateFixture(App, () => {}, 1, [TestCmpt]);
expect(fixture.html).toEqual('<test-cmpt>content</test-cmpt>');
});
@ -717,23 +764,25 @@ describe('render3 integration test', () => {
}
}
`<ng-template testDirective>
<ng-container>
<ng-container>
<ng-container>
content
</ng-container>
</ng-container>
</ng-container>
</ng-template>`;
/**
* <ng-template testDirective>
* <ng-container>
* <ng-container>
* <ng-container>
* content
* </ng-container>
* </ng-container>
* </ng-container>
* </ng-template>
*/
const TestCmpt = createComponent('test-cmpt', function(rf: RenderFlags) {
if (rf & RenderFlags.Create) {
template(0, embeddedTemplate, null, [AttributeMarker.SelectOnly, 'testDirective']);
template(0, embeddedTemplate, 4, null, [AttributeMarker.SelectOnly, 'testDirective']);
}
if (rf & RenderFlags.Update) {
testDirective = loadDirective<TestDirective>(0);
}
}, [TestDirective]);
}, 1, [TestDirective]);
function App() { element(0, 'test-cmpt'); }
@ -780,13 +829,12 @@ describe('render3 integration test', () => {
elementEnd();
}
const fixture = new TemplateFixture(Template, () => {}, [Directive]);
const fixture = new TemplateFixture(Template, () => {}, 2, [Directive]);
expect(fixture.html).toEqual('<div></div>');
expect(directive !.elRef.nativeElement.nodeType).toBe(Node.COMMENT_NODE);
});
it('should not set any attributes', () => {
/**
* <div><ng-container id="foo"></ng-container></div>
*/
@ -799,12 +847,11 @@ describe('render3 integration test', () => {
elementEnd();
}
const fixture = new TemplateFixture(Template);
const fixture = new TemplateFixture(Template, () => {}, 2);
expect(fixture.html).toEqual('<div></div>');
});
it('should throw when trying to add event listener', () => {
/**
* <div><ng-container (click)="..."></ng-container></div>
*/
@ -820,7 +867,7 @@ describe('render3 integration test', () => {
elementEnd();
}
expect(() => { new TemplateFixture(Template); }).toThrow();
expect(() => { new TemplateFixture(Template, () => {}, 2); }).toThrow();
});
});
@ -846,7 +893,7 @@ describe('render3 integration test', () => {
containerRefreshStart(0);
{
if (ctx.label != null) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
text(0);
}
@ -868,7 +915,7 @@ describe('render3 integration test', () => {
}
containerRefreshStart(0);
{
const rf0 = embeddedViewStart(0);
const rf0 = embeddedViewStart(0, 1);
{ showLabel(rf0, {label: ctx.tree.beforeLabel}); }
embeddedViewEnd();
}
@ -876,7 +923,7 @@ describe('render3 integration test', () => {
containerRefreshStart(1);
{
for (let subTree of ctx.tree.subTrees || []) {
const rf0 = embeddedViewStart(0);
const rf0 = embeddedViewStart(0, 1);
{ showTree(rf0, {tree: subTree}); }
embeddedViewEnd();
}
@ -884,7 +931,7 @@ describe('render3 integration test', () => {
containerRefreshEnd();
containerRefreshStart(2);
{
const rf0 = embeddedViewStart(0);
const rf0 = embeddedViewStart(0, 1);
{ showLabel(rf0, {label: ctx.tree.afterLabel}); }
embeddedViewEnd();
}
@ -899,6 +946,7 @@ describe('render3 integration test', () => {
static ngComponentDef = defineComponent({
selectors: [['child']],
type: ChildComponent,
consts: 3,
template: function ChildComponentTemplate(
rf: RenderFlags, ctx: {beforeTree: Tree, afterTree: Tree}) {
if (rf & RenderFlags.Create) {
@ -909,14 +957,14 @@ describe('render3 integration test', () => {
}
containerRefreshStart(0);
{
const rf0 = embeddedViewStart(0);
const rf0 = embeddedViewStart(0, 1);
{ showTree(rf0, {tree: ctx.beforeTree}); }
embeddedViewEnd();
}
containerRefreshEnd();
containerRefreshStart(2);
{
const rf0 = embeddedViewStart(0);
const rf0 = embeddedViewStart(0, 1);
{ showTree(rf0, {tree: ctx.afterTree}); }
embeddedViewEnd();
}
@ -938,7 +986,7 @@ describe('render3 integration test', () => {
elementProperty(0, 'afterTree', bind(ctx.afterTree));
containerRefreshStart(1);
{
const rf0 = embeddedViewStart(0);
const rf0 = embeddedViewStart(0, 1);
{ showTree(rf0, {tree: ctx.projectedTree}); }
embeddedViewEnd();
}
@ -954,14 +1002,14 @@ describe('render3 integration test', () => {
afterTree: {afterLabel: 'z'}
};
const defs = [ChildComponent];
expect(renderToHtml(parentTemplate, ctx, defs)).toEqual('<child>apz</child>');
expect(renderToHtml(parentTemplate, ctx, 2, defs)).toEqual('<child>apz</child>');
ctx.projectedTree = {subTrees: [{}, {}, {subTrees: [{}, {}]}, {}]};
ctx.beforeTree.subTrees !.push({afterLabel: 'b'});
expect(renderToHtml(parentTemplate, ctx, defs)).toEqual('<child>abz</child>');
expect(renderToHtml(parentTemplate, ctx, 2, defs)).toEqual('<child>abz</child>');
ctx.projectedTree.subTrees ![1].afterLabel = 'h';
expect(renderToHtml(parentTemplate, ctx, defs)).toEqual('<child>abhz</child>');
expect(renderToHtml(parentTemplate, ctx, 2, defs)).toEqual('<child>abhz</child>');
ctx.beforeTree.subTrees !.push({beforeLabel: 'c'});
expect(renderToHtml(parentTemplate, ctx, defs)).toEqual('<child>abchz</child>');
expect(renderToHtml(parentTemplate, ctx, 2, defs)).toEqual('<child>abchz</child>');
// To check the context easily:
// console.log(JSON.stringify(ctx));
@ -973,45 +1021,50 @@ describe('render3 integration test', () => {
describe('elementAttribute', () => {
it('should support attribute bindings', () => {
const ctx: {title: string | null} = {title: 'Hello'};
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'span');
}
if (rf & RenderFlags.Update) {
elementAttribute(0, 'title', bind(ctx.title));
}
}
}, 1);
const fixture = new ComponentFixture(App);
fixture.component.title = 'Hello';
fixture.update();
// initial binding
expect(renderToHtml(Template, ctx)).toEqual('<span title="Hello"></span>');
expect(fixture.html).toEqual('<span title="Hello"></span>');
// update binding
ctx.title = 'Hi!';
expect(renderToHtml(Template, ctx)).toEqual('<span title="Hi!"></span>');
fixture.component.title = 'Hi!';
fixture.update();
expect(fixture.html).toEqual('<span title="Hi!"></span>');
// remove attribute
ctx.title = null;
expect(renderToHtml(Template, ctx)).toEqual('<span></span>');
fixture.component.title = null;
fixture.update();
expect(fixture.html).toEqual('<span></span>');
});
it('should stringify values used attribute bindings', () => {
const ctx: {title: any} = {title: NaN};
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'span');
}
if (rf & RenderFlags.Update) {
elementAttribute(0, 'title', bind(ctx.title));
}
}
}, 1);
expect(renderToHtml(Template, ctx)).toEqual('<span title="NaN"></span>');
const fixture = new ComponentFixture(App);
fixture.component.title = NaN;
fixture.update();
expect(fixture.html).toEqual('<span title="NaN"></span>');
ctx.title = {toString: () => 'Custom toString'};
expect(renderToHtml(Template, ctx)).toEqual('<span title="Custom toString"></span>');
fixture.component.title = {toString: () => 'Custom toString'};
fixture.update();
expect(fixture.html).toEqual('<span title="Custom toString"></span>');
});
it('should update bindings', () => {
@ -1045,15 +1098,15 @@ describe('render3 integration test', () => {
}
}
let args = ['(', 0, 'a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 6, 'g', 7, ')'];
expect(renderToHtml(Template, args))
expect(renderToHtml(Template, args, 1))
.toEqual(
'<b a="(0a1b2c3d4e5f6g7)" a0="0" a1="(0)" a2="(0a1)" a3="(0a1b2)" a4="(0a1b2c3)" a5="(0a1b2c3d4)" a6="(0a1b2c3d4e5)" a7="(0a1b2c3d4e5f6)" a8="(0a1b2c3d4e5f6g7)"></b>');
args = args.reverse();
expect(renderToHtml(Template, args))
expect(renderToHtml(Template, args, 1))
.toEqual(
'<b a=")7g6f5e4d3c2b1a0(" a0="7" a1=")7(" a2=")7g6(" a3=")7g6f5(" a4=")7g6f5e4(" a5=")7g6f5e4d3(" a6=")7g6f5e4d3c2(" a7=")7g6f5e4d3c2b1(" a8=")7g6f5e4d3c2b1a0("></b>');
args = args.reverse();
expect(renderToHtml(Template, args))
expect(renderToHtml(Template, args, 1))
.toEqual(
'<b a="(0a1b2c3d4e5f6g7)" a0="0" a1="(0)" a2="(0a1)" a3="(0a1b2)" a4="(0a1b2c3)" a5="(0a1b2c3d4)" a6="(0a1b2c3d4e5)" a7="(0a1b2c3d4e5f6)" a8="(0a1b2c3d4e5f6g7)"></b>');
});
@ -1061,7 +1114,7 @@ describe('render3 integration test', () => {
it('should not update DOM if context has not changed', () => {
const ctx: {title: string | null} = {title: 'Hello'};
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
container(1);
@ -1072,7 +1125,7 @@ describe('render3 integration test', () => {
containerRefreshStart(1);
{
if (true) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 1);
{
if (rf1 & RenderFlags.Create) {
elementStart(0, 'b');
@ -1086,19 +1139,23 @@ describe('render3 integration test', () => {
}
containerRefreshEnd();
}
}
}, 2);
const fixture = new ComponentFixture(App);
fixture.component.title = 'Hello';
fixture.update();
// initial binding
expect(renderToHtml(Template, ctx))
.toEqual('<span title="Hello"><b title="Hello"></b></span>');
expect(fixture.html).toEqual('<span title="Hello"><b title="Hello"></b></span>');
// update DOM manually
containerEl.querySelector('b') !.setAttribute('title', 'Goodbye');
fixture.hostElement.querySelector('b') !.setAttribute('title', 'Goodbye');
// refresh with same binding
expect(renderToHtml(Template, ctx))
.toEqual('<span title="Hello"><b title="Goodbye"></b></span>');
fixture.update();
expect(fixture.html).toEqual('<span title="Hello"><b title="Goodbye"></b></span>');
// refresh again with same binding
expect(renderToHtml(Template, ctx))
.toEqual('<span title="Hello"><b title="Goodbye"></b></span>');
fixture.update();
expect(fixture.html).toEqual('<span title="Hello"><b title="Goodbye"></b></span>');
});
it('should support host attribute bindings', () => {
@ -1121,91 +1178,123 @@ describe('render3 integration test', () => {
});
}
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', ['hostBindingDir', '']);
}
}
}, 1, [HostBindingDir]);
const defs = [HostBindingDir];
expect(renderToHtml(Template, {}, defs))
.toEqual(`<div aria-label="some label" hostbindingdir=""></div>`);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual(`<div aria-label="some label" hostbindingdir=""></div>`);
hostBindingDir !.label = 'other label';
expect(renderToHtml(Template, {}, defs))
.toEqual(`<div aria-label="other label" hostbindingdir=""></div>`);
fixture.update();
expect(fixture.html).toEqual(`<div aria-label="other label" hostbindingdir=""></div>`);
});
});
describe('elementStyle', () => {
it('should support binding to styles', () => {
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
elementStyling(null, ['border-color']);
elementEnd();
}
if (rf & RenderFlags.Update) {
elementStyleProp(0, 0, ctx);
elementStyleProp(0, 0, ctx.color);
elementStylingApply(0);
}
}
}, 1);
expect(renderToHtml(Template, 'red')).toEqual('<span style="border-color: red;"></span>');
expect(renderToHtml(Template, 'green'))
.toEqual('<span style="border-color: green;"></span>');
expect(renderToHtml(Template, null)).toEqual('<span></span>');
const fixture = new ComponentFixture(App);
fixture.component.color = 'red';
fixture.update();
expect(fixture.html).toEqual('<span style="border-color: red;"></span>');
fixture.component.color = 'green';
fixture.update();
expect(fixture.html).toEqual('<span style="border-color: green;"></span>');
fixture.component.color = null;
fixture.update();
expect(fixture.html).toEqual('<span></span>');
});
it('should support binding to styles with suffix', () => {
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
elementStyling(null, ['font-size']);
elementEnd();
}
if (rf & RenderFlags.Update) {
elementStyleProp(0, 0, ctx, 'px');
elementStyleProp(0, 0, ctx.time, 'px');
elementStylingApply(0);
}
}
}, 1);
expect(renderToHtml(Template, '100')).toEqual('<span style="font-size: 100px;"></span>');
expect(renderToHtml(Template, 200)).toEqual('<span style="font-size: 200px;"></span>');
expect(renderToHtml(Template, null)).toEqual('<span></span>');
const fixture = new ComponentFixture(App);
fixture.component.time = '100';
fixture.update();
expect(fixture.html).toEqual('<span style="font-size: 100px;"></span>');
fixture.component.time = 200;
fixture.update();
expect(fixture.html).toEqual('<span style="font-size: 200px;"></span>');
fixture.component.time = null;
fixture.update();
expect(fixture.html).toEqual('<span></span>');
});
});
describe('elementClass', () => {
it('should support CSS class toggle', () => {
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
elementStyling(['active']);
elementEnd();
}
if (rf & RenderFlags.Update) {
elementClassProp(0, 0, ctx);
elementClassProp(0, 0, ctx.class);
elementStylingApply(0);
}
}
}, 1);
expect(renderToHtml(Template, true)).toEqual('<span class="active"></span>');
expect(renderToHtml(Template, false)).toEqual('<span class=""></span>');
const fixture = new ComponentFixture(App);
fixture.component.class = true;
fixture.update();
expect(fixture.html).toEqual('<span class="active"></span>');
fixture.component.class = false;
fixture.update();
expect(fixture.html).toEqual('<span class=""></span>');
// truthy values
expect(renderToHtml(Template, 'a_string')).toEqual('<span class="active"></span>');
expect(renderToHtml(Template, 10)).toEqual('<span class="active"></span>');
fixture.component.class = 'a_string';
fixture.update();
expect(fixture.html).toEqual('<span class="active"></span>');
fixture.component.class = 10;
fixture.update();
expect(fixture.html).toEqual('<span class="active"></span>');
// falsy values
expect(renderToHtml(Template, '')).toEqual('<span class=""></span>');
expect(renderToHtml(Template, 0)).toEqual('<span class=""></span>');
fixture.component.class = '';
fixture.update();
expect(fixture.html).toEqual('<span class=""></span>');
fixture.component.class = 0;
fixture.update();
expect(fixture.html).toEqual('<span class=""></span>');
});
it('should work correctly with existing static classes', () => {
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'span');
elementStyling(
@ -1213,13 +1302,19 @@ describe('render3 integration test', () => {
elementEnd();
}
if (rf & RenderFlags.Update) {
elementClassProp(0, 1, ctx);
elementClassProp(0, 1, ctx.class);
elementStylingApply(0);
}
}
}, 1);
expect(renderToHtml(Template, true)).toEqual('<span class="existing active"></span>');
expect(renderToHtml(Template, false)).toEqual('<span class="existing"></span>');
const fixture = new ComponentFixture(App);
fixture.component.class = true;
fixture.update();
expect(fixture.html).toEqual('<span class="existing active"></span>');
fixture.component.class = false;
fixture.update();
expect(fixture.html).toEqual('<span class="existing"></span>');
});
});
});
@ -1240,7 +1335,7 @@ describe('render3 integration test', () => {
containerRefreshStart(0);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
element(0, 'div');
}
@ -1253,7 +1348,7 @@ describe('render3 integration test', () => {
expect((Template as any).ngPrivateData).toBeUndefined();
renderToHtml(Template, {condition: true});
renderToHtml(Template, {condition: true}, 1);
const oldTemplateData = (Template as any).ngPrivateData;
const oldContainerData = (oldTemplateData as any).data[HEADER_OFFSET];
@ -1261,8 +1356,8 @@ describe('render3 integration test', () => {
expect(oldContainerData).not.toBeNull();
expect(oldElementData).not.toBeNull();
renderToHtml(Template, {condition: false});
renderToHtml(Template, {condition: true});
renderToHtml(Template, {condition: false}, 1);
renderToHtml(Template, {condition: true}, 1);
const newTemplateData = (Template as any).ngPrivateData;
const newContainerData = (oldTemplateData as any).data[HEADER_OFFSET];
@ -1281,6 +1376,7 @@ describe('render3 integration test', () => {
type: SanitizationComp,
selectors: [['sanitize-this']],
factory: () => new SanitizationComp(),
consts: 1,
template: (rf: RenderFlags, ctx: SanitizationComp) => {
if (rf & RenderFlags.Create) {
element(0, 'a');

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,7 @@ describe('event listeners', () => {
static ngComponentDef = defineComponent({
type: MyComp,
selectors: [['comp']],
consts: 2,
/** <button (click)="onClick()"> Click me </button> */
template: function CompTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
@ -65,6 +66,7 @@ describe('event listeners', () => {
type: PreventDefaultComp,
selectors: [['prevent-default-comp']],
factory: () => new PreventDefaultComp(),
consts: 2,
/** <button (click)="onClick($event)">Click</button> */
template: (rf: RenderFlags, ctx: PreventDefaultComp) => {
if (rf & RenderFlags.Create) {
@ -146,7 +148,7 @@ describe('event listeners', () => {
onClick: function() { this.counter++; },
onClick2: function() { this.counter2++; }
};
renderToHtml(Template, ctx);
renderToHtml(Template, ctx, 2);
const button = containerEl.querySelector('button') !;
button.click();
@ -173,7 +175,7 @@ describe('event listeners', () => {
}
const ctx = {showing: false};
renderToHtml(Template, ctx);
renderToHtml(Template, ctx, 2);
const button = containerEl.querySelector('button') !;
button.click();
@ -198,7 +200,7 @@ describe('event listeners', () => {
containerRefreshStart(0);
{
if (ctx.showing) {
if (embeddedViewStart(1)) {
if (embeddedViewStart(1, 2)) {
elementStart(0, 'button');
{
listener('click', function() { return ctx.onClick(); });
@ -214,7 +216,7 @@ describe('event listeners', () => {
}
let comp = new MyComp();
renderToHtml(Template, comp);
renderToHtml(Template, comp, 1);
const button = containerEl.querySelector('button') !;
button.click();
@ -225,7 +227,7 @@ describe('event listeners', () => {
// the listener should be removed when the view is removed
comp.showing = false;
renderToHtml(Template, comp);
renderToHtml(Template, comp, 1);
button.click();
expect(comp.counter).toEqual(2);
});
@ -247,6 +249,7 @@ describe('event listeners', () => {
type: AppComp,
selectors: [['app-comp']],
factory: () => new AppComp(),
consts: 1,
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
container(0);
@ -255,7 +258,7 @@ describe('event listeners', () => {
containerRefreshStart(0);
{
if (ctx.showing) {
if (embeddedViewStart(0)) {
if (embeddedViewStart(0, 2)) {
elementStart(0, 'button');
{
listener('click', function() { return ctx.onClick(); });
@ -306,6 +309,7 @@ describe('event listeners', () => {
type: AppComp,
selectors: [['app-comp']],
factory: () => new AppComp(),
consts: 1,
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
container(0);
@ -314,7 +318,7 @@ describe('event listeners', () => {
containerRefreshStart(0);
{
for (let i = 0; i < ctx.buttons; i++) {
if (embeddedViewStart(0)) {
if (embeddedViewStart(0, 2)) {
elementStart(0, 'button');
{
listener('click', function() { return ctx.onClick(i); });
@ -367,6 +371,7 @@ describe('event listeners', () => {
type: AppComp,
selectors: [['app-comp']],
factory: () => new AppComp(),
consts: 1,
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
container(0);
@ -375,7 +380,7 @@ describe('event listeners', () => {
containerRefreshStart(0);
{
for (let i = 0; i < ctx.buttons; i++) {
if (embeddedViewStart(1)) {
if (embeddedViewStart(1, 2)) {
elementStart(0, 'button');
{
listener('click', function() { return ctx.onClick(i); });
@ -437,7 +442,7 @@ describe('event listeners', () => {
}
}
renderToHtml(Template, {}, [HostListenerDir]);
renderToHtml(Template, {}, 2, [HostListenerDir]);
const button = containerEl.querySelector('button') !;
button.click();
expect(events).toEqual(['click!']);
@ -464,7 +469,7 @@ describe('event listeners', () => {
containerRefreshStart(0);
{
if (ctx.showing) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 2);
if (rf1 & RenderFlags.Create) {
text(0, 'Hello');
container(1);
@ -473,7 +478,7 @@ describe('event listeners', () => {
containerRefreshStart(1);
{
if (ctx.button) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 2);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'button');
{
@ -495,7 +500,7 @@ describe('event listeners', () => {
}
const comp = {showing: true, counter: 0, button: true, onClick: function() { this.counter++; }};
renderToHtml(Template, comp);
renderToHtml(Template, comp, 1);
const button = containerEl.querySelector('button') !;
button.click();
@ -503,7 +508,7 @@ describe('event listeners', () => {
// the child view listener should be removed when the parent view is removed
comp.showing = false;
renderToHtml(Template, comp);
renderToHtml(Template, comp, 1);
button.click();
expect(comp.counter).toEqual(1);
});
@ -528,7 +533,7 @@ describe('event listeners', () => {
containerRefreshStart(0);
{
if (ctx.showing) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 3);
if (rf1 & RenderFlags.Create) {
text(0, 'Hello');
element(1, 'comp');
@ -542,7 +547,7 @@ describe('event listeners', () => {
}
const ctx = {showing: true};
renderToHtml(Template, ctx, [MyComp]);
renderToHtml(Template, ctx, 1, [MyComp]);
const buttons = containerEl.querySelectorAll('button') !;
buttons[0].click();
@ -553,7 +558,7 @@ describe('event listeners', () => {
// the child view listener should be removed when the parent view is removed
ctx.showing = false;
renderToHtml(Template, ctx, [MyComp]);
renderToHtml(Template, ctx, 1, [MyComp]);
buttons[0].click();
buttons[1].click();
expect(comps[0] !.counter).toEqual(1);
@ -581,7 +586,7 @@ describe('event listeners', () => {
containerRefreshStart(0);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 3);
if (rf1 & RenderFlags.Create) {
text(0, 'Hello');
container(1);
@ -591,7 +596,7 @@ describe('event listeners', () => {
containerRefreshStart(1);
{
if (ctx.sub1) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 2);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'button');
{
@ -607,7 +612,7 @@ describe('event listeners', () => {
containerRefreshStart(2);
{
if (ctx.sub2) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 2);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'button');
{
@ -629,7 +634,7 @@ describe('event listeners', () => {
}
const ctx = {condition: true, counter1: 0, counter2: 0, sub1: true, sub2: true};
renderToHtml(Template, ctx);
renderToHtml(Template, ctx, 1);
const buttons = containerEl.querySelectorAll('button') !;
buttons[0].click();
@ -640,7 +645,7 @@ describe('event listeners', () => {
// the child view listeners should be removed when the parent view is removed
ctx.condition = false;
renderToHtml(Template, ctx);
renderToHtml(Template, ctx, 1);
buttons[0].click();
buttons[1].click();
expect(ctx.counter1).toEqual(1);

View File

@ -27,6 +27,7 @@ describe('outputs', () => {
type: ButtonToggle,
selectors: [['button-toggle']],
template: function(rf: RenderFlags, ctx: any) {},
consts: 0,
factory: () => buttonToggle = new ButtonToggle(),
outputs: {change: 'change', resetStream: 'reset'}
});
@ -52,6 +53,7 @@ describe('outputs', () => {
static ngComponentDef = defineComponent({
type: DestroyComp,
selectors: [['destroy-comp']],
consts: 0,
template: function(rf: RenderFlags, ctx: any) {},
factory: () => destroyComp = new DestroyComp()
});
@ -86,7 +88,7 @@ describe('outputs', () => {
let counter = 0;
const ctx = {onChange: () => counter++};
renderToHtml(Template, ctx, deps);
renderToHtml(Template, ctx, 1, deps);
buttonToggle !.change.next();
expect(counter).toEqual(1);
@ -111,7 +113,7 @@ describe('outputs', () => {
let counter = 0;
let resetCounter = 0;
const ctx = {onChange: () => counter++, onReset: () => resetCounter++};
renderToHtml(Template, ctx, deps);
renderToHtml(Template, ctx, 1, deps);
buttonToggle !.change.next();
expect(counter).toEqual(1);
@ -133,7 +135,7 @@ describe('outputs', () => {
}
const ctx = {counter: 0};
renderToHtml(Template, ctx, deps);
renderToHtml(Template, ctx, 1, deps);
buttonToggle !.change.next();
expect(ctx.counter).toEqual(1);
@ -158,7 +160,7 @@ describe('outputs', () => {
containerRefreshStart(0);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'button-toggle');
{
@ -175,13 +177,13 @@ describe('outputs', () => {
let counter = 0;
const ctx = {onChange: () => counter++, condition: true};
renderToHtml(Template, ctx, deps);
renderToHtml(Template, ctx, 1, deps);
buttonToggle !.change.next();
expect(counter).toEqual(1);
ctx.condition = false;
renderToHtml(Template, ctx, deps);
renderToHtml(Template, ctx, 1, deps);
buttonToggle !.change.next();
expect(counter).toEqual(1);
@ -205,14 +207,14 @@ describe('outputs', () => {
containerRefreshStart(0);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
container(0);
}
containerRefreshStart(0);
{
if (ctx.condition2) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'button-toggle');
{
@ -233,13 +235,13 @@ describe('outputs', () => {
let counter = 0;
const ctx = {onChange: () => counter++, condition: true, condition2: true};
renderToHtml(Template, ctx, deps);
renderToHtml(Template, ctx, 1, deps);
buttonToggle !.change.next();
expect(counter).toEqual(1);
ctx.condition = false;
renderToHtml(Template, ctx, deps);
renderToHtml(Template, ctx, 1, deps);
buttonToggle !.change.next();
expect(counter).toEqual(1);
@ -261,7 +263,7 @@ describe('outputs', () => {
containerRefreshStart(0);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 4);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'button');
{
@ -286,7 +288,7 @@ describe('outputs', () => {
let clickCounter = 0;
let changeCounter = 0;
const ctx = {condition: true, onChange: () => changeCounter++, onClick: () => clickCounter++};
renderToHtml(Template, ctx, deps);
renderToHtml(Template, ctx, 1, deps);
buttonToggle !.change.next();
expect(changeCounter).toEqual(1);
@ -298,7 +300,7 @@ describe('outputs', () => {
expect(clickCounter).toEqual(1);
ctx.condition = false;
renderToHtml(Template, ctx, deps);
renderToHtml(Template, ctx, 1, deps);
expect(destroyComp !.events).toEqual(['destroy']);
@ -320,7 +322,7 @@ describe('outputs', () => {
}
let counter = 0;
renderToHtml(Template, {counter, onClick: () => counter++}, deps);
renderToHtml(Template, {counter, onClick: () => counter++}, 1, deps);
// To match current Angular behavior, the click listener is still
// set up in addition to any matching outputs.
@ -345,7 +347,7 @@ describe('outputs', () => {
}
let counter = 0;
renderToHtml(Template, {counter, onChange: () => counter++}, deps);
renderToHtml(Template, {counter, onChange: () => counter++}, 1, deps);
buttonToggle !.change.next();
expect(counter).toEqual(1);
@ -385,10 +387,10 @@ describe('outputs', () => {
let counter = 0;
const deps = [ButtonToggle, OtherChangeDir];
renderToHtml(Template, {counter, onChange: () => counter++, change: true}, deps);
renderToHtml(Template, {counter, onChange: () => counter++, change: true}, 1, deps);
expect(otherDir !.change).toEqual(true);
renderToHtml(Template, {counter, onChange: () => counter++, change: false}, deps);
renderToHtml(Template, {counter, onChange: () => counter++, change: false}, 1, deps);
expect(otherDir !.change).toEqual(false);
buttonToggle !.change.next();
@ -419,7 +421,7 @@ describe('outputs', () => {
containerRefreshStart(2);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'button-toggle');
{
@ -429,7 +431,7 @@ describe('outputs', () => {
}
embeddedViewEnd();
} else {
if (embeddedViewStart(1)) {
if (embeddedViewStart(1, 1)) {
elementStart(0, 'div', ['otherDir', '']);
{
listener('change', function() { return ctx.onChange(); });
@ -445,13 +447,13 @@ describe('outputs', () => {
let counter = 0;
const ctx = {condition: true, onChange: () => counter++, onClick: () => {}};
renderToHtml(Template, ctx, deps);
renderToHtml(Template, ctx, 3, deps);
buttonToggle !.change.next();
expect(counter).toEqual(1);
ctx.condition = false;
renderToHtml(Template, ctx, deps);
renderToHtml(Template, ctx, 3, deps);
expect(counter).toEqual(1);
otherDir !.changeStream.next();

View File

@ -45,7 +45,7 @@ describe('pipe', () => {
}
person.init('bob', null);
expect(renderToHtml(Template, person, null, pipes)).toEqual('bob state:0');
expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bob state:0');
});
it('should throw if pipe is not found', () => {
@ -57,7 +57,7 @@ describe('pipe', () => {
if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', pipeBind1(1, 1, ctx.value), ''));
}
}, [], pipes);
}, 2, [], pipes);
expect(() => {
const fixture = new ComponentFixture(App);
@ -103,7 +103,7 @@ describe('pipe', () => {
directive = loadDirective(0);
}
}
renderToHtml(Template, 'a', [MyDir], [DoublePipe]);
renderToHtml(Template, 'a', 2, [MyDir], [DoublePipe]);
expect(directive !.dirProp).toEqual('aa');
});
@ -120,7 +120,7 @@ describe('pipe', () => {
}
person.init('value', new Address('two'));
expect(renderToHtml(Template, person, null, pipes)).toEqual('value one two default');
expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('value one two default');
});
it('should support calling pipes with different number of arguments', () => {
@ -138,7 +138,7 @@ describe('pipe', () => {
}
person.init('value', null);
expect(renderToHtml(Template, person, null, pipes)).toEqual('value a b default 0 1 2');
expect(renderToHtml(Template, person, 3, null, pipes)).toEqual('value a b default 0 1 2');
});
it('should do nothing when no change', () => {
@ -164,11 +164,11 @@ describe('pipe', () => {
}
}
renderToHtml(Template, person, null, [IdentityPipe], rendererFactory2);
renderToHtml(Template, person, 2, null, [IdentityPipe], rendererFactory2);
expect(renderLog.log).toEqual(['someProp=Megatron']);
renderLog.clear();
renderToHtml(Template, person, null, pipes, rendererFactory2);
renderToHtml(Template, person, 2, null, pipes, rendererFactory2);
expect(renderLog.log).toEqual([]);
});
@ -186,18 +186,18 @@ describe('pipe', () => {
// change from undefined -> null
person.name = null;
expect(renderToHtml(Template, person, null, pipes)).toEqual('null state:0');
expect(renderToHtml(Template, person, null, pipes)).toEqual('null state:0');
expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('null state:0');
expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('null state:0');
// change from null -> some value
person.name = 'bob';
expect(renderToHtml(Template, person, null, pipes)).toEqual('bob state:1');
expect(renderToHtml(Template, person, null, pipes)).toEqual('bob state:1');
expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bob state:1');
expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bob state:1');
// change from some value -> some other value
person.name = 'bart';
expect(renderToHtml(Template, person, null, pipes)).toEqual('bart state:2');
expect(renderToHtml(Template, person, null, pipes)).toEqual('bart state:2');
expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bart state:2');
expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bart state:2');
});
});
@ -214,8 +214,8 @@ describe('pipe', () => {
}
person.name = 'bob';
expect(renderToHtml(Template, person, null, pipes)).toEqual('bob state:0');
expect(renderToHtml(Template, person, null, pipes)).toEqual('bob state:1');
expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bob state:0');
expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bob state:1');
});
it('should not cache impure pipes', () => {
@ -236,7 +236,7 @@ describe('pipe', () => {
containerRefreshStart(4);
{
for (let i of [1, 2]) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 2);
{
if (rf1 & RenderFlags.Create) {
elementStart(0, 'div');
@ -256,7 +256,7 @@ describe('pipe', () => {
}
const pipeInstances: CountingImpurePipe[] = [];
renderToHtml(Template, {}, null, pipes, rendererFactory2);
renderToHtml(Template, {}, 5, null, pipes, rendererFactory2);
expect(pipeInstances.length).toEqual(4);
expect(pipeInstances[0]).toBeAnInstanceOf(CountingImpurePipe);
expect(pipeInstances[1]).toBeAnInstanceOf(CountingImpurePipe);
@ -291,7 +291,7 @@ describe('pipe', () => {
containerRefreshStart(0);
{
if (person.age > 20) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 2);
{
if (rf1 & RenderFlags.Create) {
text(0);
@ -310,20 +310,20 @@ describe('pipe', () => {
const pipes = [PipeWithOnDestroy];
person.age = 25;
renderToHtml(Template, person, null, pipes);
renderToHtml(Template, person, 1, null, pipes);
person.age = 15;
renderToHtml(Template, person, null, pipes);
renderToHtml(Template, person, 1, null, pipes);
expect(log).toEqual(['pipeWithOnDestroy - ngOnDestroy']);
log = [];
person.age = 30;
renderToHtml(Template, person, null, pipes);
renderToHtml(Template, person, 1, null, pipes);
expect(log).toEqual([]);
log = [];
person.age = 10;
renderToHtml(Template, person, null, pipes);
renderToHtml(Template, person, 1, null, pipes);
expect(log).toEqual(['pipeWithOnDestroy - ngOnDestroy']);
});
});

View File

@ -8,26 +8,33 @@
import {EventEmitter} from '@angular/core';
import {defineComponent, defineDirective, tick} from '../../src/render3/index';
import {AttributeMarker, defineComponent, defineDirective, tick} from '../../src/render3/index';
import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, listener, loadDirective, reference, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {pureFunction1, pureFunction2} from '../../src/render3/pure_function';
import {ComponentFixture, renderToHtml} from './render_util';
import {ComponentFixture, TemplateFixture, createComponent, renderToHtml} from './render_util';
describe('elementProperty', () => {
it('should support bindings to properties', () => {
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'span');
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind(ctx));
elementProperty(0, 'id', bind(ctx.id));
}
}
}, 1);
expect(renderToHtml(Template, 'testId')).toEqual('<span id="testId"></span>');
expect(renderToHtml(Template, 'otherId')).toEqual('<span id="otherId"></span>');
const fixture = new ComponentFixture(App);
fixture.component.id = 'testId';
fixture.update();
expect(fixture.html).toEqual('<span id="testId"></span>');
fixture.component.id = 'otherId';
fixture.update();
expect(fixture.html).toEqual('<span id="otherId"></span>');
});
it('should support creation time bindings to properties', () => {
@ -48,22 +55,28 @@ describe('elementProperty', () => {
}
}
expect(renderToHtml(Template, 'cheapId')).toEqual('<span id="cheapId"></span>');
expect(renderToHtml(Template, 'expensiveId')).toEqual('<span id="cheapId"></span>');
expect(renderToHtml(Template, 'cheapId', 1)).toEqual('<span id="cheapId"></span>');
expect(renderToHtml(Template, 'expensiveId', 1)).toEqual('<span id="cheapId"></span>');
});
it('should support interpolation for properties', () => {
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'span');
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', interpolation1('_', ctx, '_'));
elementProperty(0, 'id', interpolation1('_', ctx.id, '_'));
}
}
}, 1);
expect(renderToHtml(Template, 'testId')).toEqual('<span id="_testId_"></span>');
expect(renderToHtml(Template, 'otherId')).toEqual('<span id="_otherId_"></span>');
const fixture = new ComponentFixture(App);
fixture.component.id = 'testId';
fixture.update();
expect(fixture.html).toEqual('<span id="_testId_"></span>');
fixture.component.id = 'otherId';
fixture.update();
expect(fixture.html).toEqual('<span id="_otherId_"></span>');
});
it('should support host bindings on root component', () => {
@ -74,6 +87,7 @@ describe('elementProperty', () => {
type: HostBindingComp,
selectors: [['host-binding-comp']],
factory: () => new HostBindingComp(),
consts: 0,
hostBindings: (dirIndex: number, elIndex: number) => {
const instance = loadDirective(dirIndex) as HostBindingComp;
elementProperty(elIndex, 'id', bind(instance.id));
@ -152,7 +166,7 @@ describe('elementProperty', () => {
it('should check input properties before setting (directives)', () => {
/** <button myButton otherDir [id]="id" [disabled]="isDisabled">Click me</button> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'button', ['otherDir', '', 'myButton', '']);
{ text(1, 'Click me'); }
@ -162,18 +176,20 @@ describe('elementProperty', () => {
elementProperty(0, 'disabled', bind(ctx.isDisabled));
elementProperty(0, 'id', bind(ctx.id));
}
}
}, 2, deps);
const ctx: any = {isDisabled: true, id: 0};
expect(renderToHtml(Template, ctx, deps))
.toEqual(`<button mybutton="" otherdir="">Click me</button>`);
const fixture = new ComponentFixture(App);
fixture.component.isDisabled = true;
fixture.component.id = 0;
fixture.update();
expect(fixture.html).toEqual(`<button mybutton="" otherdir="">Click me</button>`);
expect(button !.disabled).toEqual(true);
expect(otherDir !.id).toEqual(0);
ctx.isDisabled = false;
ctx.id = 1;
expect(renderToHtml(Template, ctx, deps))
.toEqual(`<button mybutton="" otherdir="">Click me</button>`);
fixture.component.isDisabled = false;
fixture.component.id = 1;
fixture.update();
expect(fixture.html).toEqual(`<button mybutton="" otherdir="">Click me</button>`);
expect(button !.disabled).toEqual(false);
expect(otherDir !.id).toEqual(1);
});
@ -181,7 +197,7 @@ describe('elementProperty', () => {
it('should support mixed element properties and input properties', () => {
/** <button myButton [id]="id" [disabled]="isDisabled">Click me</button> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'button', ['myButton', '']);
{ text(1, 'Click me'); }
@ -191,18 +207,20 @@ describe('elementProperty', () => {
elementProperty(0, 'disabled', bind(ctx.isDisabled));
elementProperty(0, 'id', bind(ctx.id));
}
}
}, 2, deps);
const ctx: any = {isDisabled: true, id: 0};
expect(renderToHtml(Template, ctx, deps))
.toEqual(`<button id="0" mybutton="">Click me</button>`);
const fixture = new ComponentFixture(App);
fixture.component.isDisabled = true;
fixture.component.id = 0;
fixture.update();
expect(fixture.html).toEqual(`<button id="0" mybutton="">Click me</button>`);
expect(button !.disabled).toEqual(true);
ctx.isDisabled = false;
ctx.id = 1;
expect(renderToHtml(Template, ctx, deps))
.toEqual(`<button id="1" mybutton="">Click me</button>`);
fixture.component.isDisabled = false;
fixture.component.id = 1;
fixture.update();
expect(fixture.html).toEqual(`<button id="1" mybutton="">Click me</button>`);
expect(button !.disabled).toEqual(false);
});
@ -216,6 +234,7 @@ describe('elementProperty', () => {
static ngComponentDef = defineComponent({
type: Comp,
selectors: [['comp']],
consts: 0,
template: function(rf: RenderFlags, ctx: any) {},
factory: () => comp = new Comp(),
inputs: {id: 'id'}
@ -223,27 +242,31 @@ describe('elementProperty', () => {
}
/** <comp [id]="id"></comp> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'comp');
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind(ctx.id));
}
}
}, 1, [Comp]);
const deps = [Comp];
expect(renderToHtml(Template, {id: 1}, deps)).toEqual(`<comp></comp>`);
const fixture = new ComponentFixture(App);
fixture.component.id = 1;
fixture.update();
expect(fixture.html).toEqual(`<comp></comp>`);
expect(comp !.id).toEqual(1);
expect(renderToHtml(Template, {id: 2}, deps)).toEqual(`<comp></comp>`);
fixture.component.id = 2;
fixture.update();
expect(fixture.html).toEqual(`<comp></comp>`);
expect(comp !.id).toEqual(2);
});
it('should support two input properties with the same name', () => {
/** <button myButton otherDisabledDir [disabled]="isDisabled">Click me</button> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'button', ['myButton', '', 'otherDisabledDir', '']);
{ text(1, 'Click me'); }
@ -252,28 +275,29 @@ describe('elementProperty', () => {
if (rf & RenderFlags.Update) {
elementProperty(0, 'disabled', bind(ctx.isDisabled));
}
}
}, 2, deps);
const ctx: any = {isDisabled: true};
expect(renderToHtml(Template, ctx, deps))
.toEqual(`<button mybutton="" otherdisableddir="">Click me</button>`);
const fixture = new ComponentFixture(App);
fixture.component.isDisabled = true;
fixture.update();
expect(fixture.html).toEqual(`<button mybutton="" otherdisableddir="">Click me</button>`);
expect(button !.disabled).toEqual(true);
expect(otherDisabledDir !.disabled).toEqual(true);
ctx.isDisabled = false;
expect(renderToHtml(Template, ctx, deps))
.toEqual(`<button mybutton="" otherdisableddir="">Click me</button>`);
fixture.component.isDisabled = false;
fixture.update();
expect(fixture.html).toEqual(`<button mybutton="" otherdisableddir="">Click me</button>`);
expect(button !.disabled).toEqual(false);
expect(otherDisabledDir !.disabled).toEqual(false);
});
it('should set input property if there is an output first', () => {
/** <button otherDir [id]="id" (click)="onClick()">Click me</button> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'button', ['otherDir', '']);
{
listener('click', ctx.onClick.bind(ctx));
listener('click', () => ctx.onClick());
text(1, 'Click me');
}
elementEnd();
@ -281,18 +305,22 @@ describe('elementProperty', () => {
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind(ctx.id));
}
}
}, 2, deps);
const fixture = new ComponentFixture(App);
let counter = 0;
const ctx: any = {id: 1, onClick: () => counter++};
expect(renderToHtml(Template, ctx, deps)).toEqual(`<button otherdir="">Click me</button>`);
fixture.component.id = 1;
fixture.component.onClick = () => counter++;
fixture.update();
expect(fixture.html).toEqual(`<button otherdir="">Click me</button>`);
expect(otherDir !.id).toEqual(1);
otherDir !.clickStream.next();
expect(counter).toEqual(1);
ctx.id = 2;
renderToHtml(Template, ctx, deps);
fixture.component.id = 2;
fixture.update();
fixture.html;
expect(otherDir !.id).toEqual(2);
});
@ -305,7 +333,7 @@ describe('elementProperty', () => {
* <button otherDir [id]="id3">Click me too</button> // inputs: {'id': [0, 'id']}
* % }
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'button', ['idDir', '']);
{ text(1, 'Click me'); }
@ -317,7 +345,7 @@ describe('elementProperty', () => {
containerRefreshStart(2);
{
if (ctx.condition) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 2);
if (rf0 & RenderFlags.Create) {
elementStart(0, 'button');
{ text(1, 'Click me too'); }
@ -328,7 +356,7 @@ describe('elementProperty', () => {
}
embeddedViewEnd();
} else {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 2);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'button', ['otherDir', '']);
{ text(1, 'Click me too'); }
@ -342,13 +370,22 @@ describe('elementProperty', () => {
}
containerRefreshEnd();
}
}
}, 3, deps);
expect(renderToHtml(Template, {condition: true, id1: 'one', id2: 'two', id3: 3}, deps))
const fixture = new ComponentFixture(App);
fixture.component.condition = true;
fixture.component.id1 = 'one';
fixture.component.id2 = 'two';
fixture.component.id3 = 3;
fixture.update();
expect(fixture.html)
.toEqual(`<button iddir="">Click me</button><button id="two">Click me too</button>`);
expect(idDir !.idNumber).toEqual('one');
expect(renderToHtml(Template, {condition: false, id1: 'four', id2: 'two', id3: 3}, deps))
fixture.component.condition = false;
fixture.component.id1 = 'four';
fixture.update();
expect(fixture.html)
.toEqual(`<button iddir="">Click me</button><button otherdir="">Click me too</button>`);
expect(idDir !.idNumber).toEqual('four');
expect(otherDir !.id).toEqual(3);
@ -393,47 +430,51 @@ describe('elementProperty', () => {
it('should set input property based on attribute if existing', () => {
/** <div role="button" myDir></div> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', ['role', 'button', 'myDir', '']);
}
}
}, 1, deps);
expect(renderToHtml(Template, {}, deps)).toEqual(`<div mydir="" role="button"></div>`);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual(`<div mydir="" role="button"></div>`);
expect(myDir !.role).toEqual('button');
});
it('should set input property and attribute if both defined', () => {
/** <div role="button" [role]="role" myDir></div> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', ['role', 'button', 'myDir', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'role', bind(ctx.role));
}
}
}, 1, deps);
expect(renderToHtml(Template, {role: 'listbox'}, deps))
.toEqual(`<div mydir="" role="button"></div>`);
const fixture = new ComponentFixture(App);
fixture.component.role = 'listbox';
fixture.update();
expect(fixture.html).toEqual(`<div mydir="" role="button"></div>`);
expect(myDir !.role).toEqual('listbox');
renderToHtml(Template, {role: 'button'}, deps);
fixture.component.role = 'button';
fixture.update();
expect(myDir !.role).toEqual('button');
});
it('should set two directive input properties based on same attribute', () => {
/** <div role="button" myDir myDirB></div> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', ['role', 'button', 'myDir', '', 'myDirB', '']);
}
}
}, 1, deps);
expect(renderToHtml(Template, {}, deps))
.toEqual(`<div mydir="" mydirb="" role="button"></div>`);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual(`<div mydir="" mydirb="" role="button"></div>`);
expect(myDir !.role).toEqual('button');
expect(dirB !.roleB).toEqual('button');
});
@ -441,14 +482,14 @@ describe('elementProperty', () => {
it('should process two attributes on same directive', () => {
/** <div role="button" dir="rtl" myDir></div> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', ['role', 'button', 'dir', 'rtl', 'myDir', '']);
}
}
}, 1, deps);
expect(renderToHtml(Template, {}, deps))
.toEqual(`<div dir="rtl" mydir="" role="button"></div>`);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual(`<div dir="rtl" mydir="" role="button"></div>`);
expect(myDir !.role).toEqual('button');
expect(myDir !.direction).toEqual('rtl');
});
@ -456,17 +497,19 @@ describe('elementProperty', () => {
it('should process attributes and outputs properly together', () => {
/** <div role="button" (change)="onChange()" myDir></div> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['role', 'button', 'myDir', '']);
{ listener('change', ctx.onChange.bind(ctx)); }
{ listener('change', () => ctx.onChange()); }
elementEnd();
}
}
}, 1, deps);
const fixture = new ComponentFixture(App);
let counter = 0;
expect(renderToHtml(Template, {onChange: () => counter++}, deps))
.toEqual(`<div mydir="" role="button"></div>`);
fixture.component.onChange = () => counter++;
fixture.update();
expect(fixture.html).toEqual(`<div mydir="" role="button"></div>`);
expect(myDir !.role).toEqual('button');
myDir !.changeStream.next();
@ -479,14 +522,15 @@ describe('elementProperty', () => {
* <div role="button" dir="rtl" myDir></div>
* <div role="listbox" myDirB></div>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', ['role', 'button', 'dir', 'rtl', 'myDir', '']);
element(1, 'div', ['role', 'listbox', 'myDirB', '']);
}
}
}, 2, deps);
expect(renderToHtml(Template, {}, deps))
const fixture = new ComponentFixture(App);
expect(fixture.html)
.toEqual(
`<div dir="rtl" mydir="" role="button"></div><div mydirb="" role="listbox"></div>`);
expect(myDir !.role).toEqual('button');
@ -504,7 +548,7 @@ describe('elementProperty', () => {
* <div role="menu"></div> // initialInputs: [null]
* % }
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', ['role', 'listbox', 'myDir', '']);
container(1);
@ -513,13 +557,13 @@ describe('elementProperty', () => {
containerRefreshStart(1);
{
if (ctx.condition) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
element(0, 'div', ['role', 'button', 'myDirB', '']);
}
embeddedViewEnd();
} else {
let rf2 = embeddedViewStart(1);
let rf2 = embeddedViewStart(1, 1);
if (rf2 & RenderFlags.Create) {
element(0, 'div', ['role', 'menu']);
}
@ -528,16 +572,20 @@ describe('elementProperty', () => {
}
containerRefreshEnd();
}
}
}, 2, deps);
expect(renderToHtml(Template, {condition: true}, deps))
const fixture = new ComponentFixture(App);
fixture.component.condition = true;
fixture.update();
expect(fixture.html)
.toEqual(`<div mydir="" role="listbox"></div><div mydirb="" role="button"></div>`);
expect(myDir !.role).toEqual('listbox');
expect(dirB !.roleB).toEqual('button');
expect((dirB !as any).role).toBeUndefined();
expect(renderToHtml(Template, {condition: false}, deps))
.toEqual(`<div mydir="" role="listbox"></div><div role="menu"></div>`);
fixture.component.condition = false;
fixture.update();
expect(fixture.html).toEqual(`<div mydir="" role="listbox"></div><div role="menu"></div>`);
expect(myDir !.role).toEqual('listbox');
});
@ -547,6 +595,7 @@ describe('elementProperty', () => {
static ngComponentDef = defineComponent({
type: Comp,
selectors: [['comp']],
consts: 3,
/** <div role="button" dir #dir="myDir"></div> {{ dir.role }} */
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
@ -568,7 +617,7 @@ describe('elementProperty', () => {
* <comp></comp>
* % }
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
container(0);
}
@ -576,7 +625,7 @@ describe('elementProperty', () => {
containerRefreshStart(0);
{
for (let i = 0; i < 2; i++) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
element(0, 'comp');
}
@ -585,9 +634,10 @@ describe('elementProperty', () => {
}
containerRefreshEnd();
}
}
}, 1, [Comp]);
expect(renderToHtml(Template, {}, [Comp]))
const fixture = new ComponentFixture(App);
expect(fixture.html)
.toEqual(
`<comp><div mydir="" role="button"></div>button</comp><comp><div mydir="" role="button"></div>button</comp>`);
});

View File

@ -23,6 +23,7 @@ describe('array literals', () => {
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory() { return myComp = new MyComp(); },
consts: 0,
template: function MyComp_Template(rf: RenderFlags, ctx: MyComp) {},
inputs: {names: 'names'}
});
@ -34,24 +35,27 @@ describe('array literals', () => {
const e0_ff = (v: any) => ['Nancy', v, 'Bess'];
/** <my-comp [names]="['Nancy', customName, 'Bess']"></my-comp> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'my-comp');
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'names', bind(pureFunction1(1, e0_ff, ctx.customName)));
}
}
}, 1, directives);
renderToHtml(Template, {customName: 'Carson'}, directives);
const fixture = new ComponentFixture(App);
fixture.component.customName = 'Carson';
fixture.update();
const firstArray = myComp !.names;
expect(firstArray).toEqual(['Nancy', 'Carson', 'Bess']);
renderToHtml(Template, {customName: 'Carson'}, directives);
fixture.update();
expect(myComp !.names).toEqual(['Nancy', 'Carson', 'Bess']);
expect(firstArray).toBe(myComp !.names);
renderToHtml(Template, {customName: 'Hannah'}, directives);
fixture.component.customName = 'Hannah';
fixture.update();
expect(myComp !.names).toEqual(['Nancy', 'Hannah', 'Bess']);
// Identity must change if binding changes
@ -60,7 +64,7 @@ describe('array literals', () => {
// The property should not be set if the exp value is the same, so artificially
// setting the property to ensure it's not overwritten.
myComp !.names = ['should not be overwritten'];
renderToHtml(Template, {customName: 'Hannah'}, directives);
fixture.update();
expect(myComp !.names).toEqual(['should not be overwritten']);
});
@ -82,12 +86,12 @@ describe('array literals', () => {
*/
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(0, IfTemplate, null, [AttributeMarker.SelectOnly, 'ngIf']);
template(0, IfTemplate, 1, null, [AttributeMarker.SelectOnly, 'ngIf']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'ngIf', bind(ctx.showing));
}
}, [MyComp, NgIf]);
}, 1, [MyComp, NgIf]);
const fixture = new ComponentFixture(App);
fixture.component.showing = true;
@ -110,6 +114,7 @@ describe('array literals', () => {
type: ManyPropComp,
selectors: [['many-prop-comp']],
factory: function ManyPropComp_Factory() { return manyPropComp = new ManyPropComp(); },
consts: 0,
template: function ManyPropComp_Template(rf: RenderFlags, ctx: ManyPropComp) {},
inputs: {names1: 'names1', names2: 'names2'}
});
@ -122,7 +127,7 @@ describe('array literals', () => {
* <many-prop-comp [names1]="['Nancy', customName]" [names2]="[customName2]">
* </many-prop-comp>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'many-prop-comp');
}
@ -130,14 +135,18 @@ describe('array literals', () => {
elementProperty(0, 'names1', bind(pureFunction1(2, e0_ff, ctx.customName)));
elementProperty(0, 'names2', bind(pureFunction1(4, e0_ff_1, ctx.customName2)));
}
}
}, 1, [ManyPropComp]);
const defs = [ManyPropComp];
renderToHtml(Template, {customName: 'Carson', customName2: 'George'}, defs);
const fixture = new ComponentFixture(App);
fixture.component.customName = 'Carson';
fixture.component.customName2 = 'George';
fixture.update();
expect(manyPropComp !.names1).toEqual(['Nancy', 'Carson']);
expect(manyPropComp !.names2).toEqual(['George']);
renderToHtml(Template, {customName: 'George', customName2: 'Carson'}, defs);
fixture.component.customName = 'George';
fixture.component.customName2 = 'Carson';
fixture.update();
expect(manyPropComp !.names1).toEqual(['Nancy', 'George']);
expect(manyPropComp !.names2).toEqual(['Carson']);
});
@ -160,6 +169,7 @@ describe('array literals', () => {
type: ParentComp,
selectors: [['parent-comp']],
factory: () => new ParentComp(),
consts: 1,
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp');
@ -174,21 +184,21 @@ describe('array literals', () => {
});
}
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'parent-comp');
element(1, 'parent-comp');
}
}
}, 2, [ParentComp]);
renderToHtml(Template, {}, [ParentComp]);
const fixture = new ComponentFixture(App);
const firstArray = myComps[0].names;
const secondArray = myComps[1].names;
expect(firstArray).toEqual(['NANCY', 'Bess']);
expect(secondArray).toEqual(['NANCY', 'Bess']);
expect(firstArray).not.toBe(secondArray);
renderToHtml(Template, {}, [ParentComp]);
fixture.update();
expect(firstArray).toEqual(['NANCY', 'Bess']);
expect(secondArray).toEqual(['NANCY', 'Bess']);
expect(firstArray).toBe(myComps[0].names);
@ -199,34 +209,40 @@ describe('array literals', () => {
const e0_ff = (v1: any, v2: any) => ['Nancy', v1, 'Bess', v2];
/** <my-comp [names]="['Nancy', customName, 'Bess', customName2]"></my-comp> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'my-comp');
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'names', bind(pureFunction2(1, e0_ff, ctx.customName, ctx.customName2)));
}
}
}, 1, directives);
renderToHtml(Template, {customName: 'Carson', customName2: 'Hannah'}, directives);
const fixture = new ComponentFixture(App);
fixture.component.customName = 'Carson';
fixture.component.customName2 = 'Hannah';
fixture.update();
const firstArray = myComp !.names;
expect(firstArray).toEqual(['Nancy', 'Carson', 'Bess', 'Hannah']);
renderToHtml(Template, {customName: 'Carson', customName2: 'Hannah'}, directives);
fixture.update();
expect(myComp !.names).toEqual(['Nancy', 'Carson', 'Bess', 'Hannah']);
expect(firstArray).toBe(myComp !.names);
renderToHtml(Template, {customName: 'George', customName2: 'Hannah'}, directives);
fixture.component.customName = 'George';
fixture.update();
expect(myComp !.names).toEqual(['Nancy', 'George', 'Bess', 'Hannah']);
expect(firstArray).not.toBe(myComp !.names);
renderToHtml(Template, {customName: 'Frank', customName2: 'Ned'}, directives);
fixture.component.customName = 'Frank';
fixture.component.customName2 = 'Ned';
fixture.update();
expect(myComp !.names).toEqual(['Nancy', 'Frank', 'Bess', 'Ned']);
// The property should not be set if the exp value is the same, so artificially
// setting the property to ensure it's not overwritten.
myComp !.names = ['should not be overwritten'];
renderToHtml(Template, {customName: 'Frank', customName2: 'Ned'}, directives);
fixture.update();
expect(myComp !.names).toEqual(['should not be overwritten']);
});
@ -288,7 +304,7 @@ describe('array literals', () => {
}
}
renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], directives);
renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], 6, directives);
expect(f3Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
expect(f4Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
expect(f5Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
@ -296,7 +312,7 @@ describe('array literals', () => {
expect(f7Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
expect(f8Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
renderToHtml(Template, ['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1', 'i1'], directives);
renderToHtml(Template, ['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1', 'i1'], 6, directives);
expect(f3Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f1', 'g1', 'h1']);
expect(f4Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e1', 'f1', 'g1', 'h1']);
expect(f5Comp !.names).toEqual(['a', 'b', 'c', 'd1', 'e1', 'f1', 'g1', 'h1']);
@ -304,7 +320,7 @@ describe('array literals', () => {
expect(f7Comp !.names).toEqual(['a', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1']);
expect(f8Comp !.names).toEqual(['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1']);
renderToHtml(Template, ['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h2', 'i1'], directives);
renderToHtml(Template, ['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h2', 'i1'], 6, directives);
expect(f3Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f1', 'g1', 'h2']);
expect(f4Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e1', 'f1', 'g1', 'h2']);
expect(f5Comp !.names).toEqual(['a', 'b', 'c', 'd1', 'e1', 'f1', 'g1', 'h2']);
@ -319,7 +335,7 @@ describe('array literals', () => {
v8: any) => ['start', v0, v1, v2, v3, v4, v5, v6, v7, v8, 'end'];
const e0_ff_1 = (v: any) => `modified_${v}`;
renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], directives);
renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], 1, directives);
/**
* <my-comp [names]="['start', v0, v1, v2, v3, `modified_${v4}`, v5, v6, v7, v8, 'end']">
* </my-comp>
@ -340,12 +356,12 @@ describe('array literals', () => {
'start', 'a', 'b', 'c', 'd', 'modified_e', 'f', 'g', 'h', 'i', 'end'
]);
renderToHtml(Template, ['a1', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], directives);
renderToHtml(Template, ['a1', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], 1, directives);
expect(myComp !.names).toEqual([
'start', 'a1', 'b', 'c', 'd', 'modified_e', 'f', 'g', 'h', 'i', 'end'
]);
renderToHtml(Template, ['a1', 'b', 'c', 'd', 'e5', 'f', 'g', 'h', 'i'], directives);
renderToHtml(Template, ['a1', 'b', 'c', 'd', 'e5', 'f', 'g', 'h', 'i'], 1, directives);
expect(myComp !.names).toEqual([
'start', 'a1', 'b', 'c', 'd', 'modified_e5', 'f', 'g', 'h', 'i', 'end'
]);
@ -363,6 +379,7 @@ describe('object literals', () => {
type: ObjectComp,
selectors: [['object-comp']],
factory: function ObjectComp_Factory() { return objectComp = new ObjectComp(); },
consts: 0,
template: function ObjectComp_Template(rf: RenderFlags, ctx: ObjectComp) {},
inputs: {config: 'config'}
});
@ -374,24 +391,27 @@ describe('object literals', () => {
const e0_ff = (v: any) => { return {duration: 500, animation: v}; };
/** <object-comp [config]="{duration: 500, animation: name}"></object-comp> */
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'object-comp');
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'config', bind(pureFunction1(1, e0_ff, ctx.name)));
}
}
}, 1, defs);
renderToHtml(Template, {name: 'slide'}, defs);
const fixture = new ComponentFixture(App);
fixture.component.name = 'slide';
fixture.update();
const firstObj = objectComp !.config;
expect(objectComp !.config).toEqual({duration: 500, animation: 'slide'});
renderToHtml(Template, {name: 'slide'}, defs);
fixture.update();
expect(objectComp !.config).toEqual({duration: 500, animation: 'slide'});
expect(firstObj).toBe(objectComp !.config);
renderToHtml(Template, {name: 'tap'}, defs);
fixture.component.name = 'tap';
fixture.update();
expect(objectComp !.config).toEqual({duration: 500, animation: 'tap'});
// Identity must change if binding changes
@ -408,7 +428,7 @@ describe('object literals', () => {
* duration: duration }]}">
* </object-comp>
*/
function Template(rf: RenderFlags, ctx: any) {
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'object-comp');
}
@ -418,36 +438,43 @@ describe('object literals', () => {
5, e0_ff, ctx.name,
pureFunction1(3, e0_ff_1, pureFunction1(1, e0_ff_2, ctx.duration)))));
}
}
}, 1, defs);
renderToHtml(Template, {name: 'slide', duration: 100}, defs);
const fixture = new ComponentFixture(App);
fixture.component.name = 'slide';
fixture.component.duration = 100;
fixture.update();
expect(objectComp !.config).toEqual({
animation: 'slide',
actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 100}]
});
const firstConfig = objectComp !.config;
renderToHtml(Template, {name: 'slide', duration: 100}, defs);
fixture.update();
expect(objectComp !.config).toEqual({
animation: 'slide',
actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 100}]
});
expect(objectComp !.config).toBe(firstConfig);
renderToHtml(Template, {name: 'slide', duration: 50}, defs);
fixture.component.duration = 50;
fixture.update();
expect(objectComp !.config).toEqual({
animation: 'slide',
actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 50}]
});
expect(objectComp !.config).not.toBe(firstConfig);
renderToHtml(Template, {name: 'tap', duration: 50}, defs);
fixture.component.name = 'tap';
fixture.update();
expect(objectComp !.config).toEqual({
animation: 'tap',
actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 50}]
});
renderToHtml(Template, {name: 'drag', duration: 500}, defs);
fixture.component.name = 'drag';
fixture.component.duration = 500;
fixture.update();
expect(objectComp !.config).toEqual({
animation: 'drag',
actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 500}]
@ -456,7 +483,7 @@ describe('object literals', () => {
// The property should not be set if the exp value is the same, so artificially
// setting the property to ensure it's not overwritten.
objectComp !.config = ['should not be overwritten'];
renderToHtml(Template, {name: 'drag', duration: 500}, defs);
fixture.update();
expect(objectComp !.config).toEqual(['should not be overwritten']);
});
@ -477,7 +504,7 @@ describe('object literals', () => {
containerRefreshStart(0);
{
for (let i = 0; i < 2; i++) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'object-comp');
objectComps.push(loadDirective(0));
@ -498,12 +525,12 @@ describe('object literals', () => {
const e0_ff = (v1: any, v2: any) => { return {opacity: v1, duration: v2}; };
const configs = [{opacity: 0, duration: 500}, {opacity: 1, duration: 600}];
renderToHtml(Template, {configs}, defs);
renderToHtml(Template, {configs}, 1, defs);
expect(objectComps[0].config).toEqual({opacity: 0, duration: 500});
expect(objectComps[1].config).toEqual({opacity: 1, duration: 600});
configs[0].duration = 1000;
renderToHtml(Template, {configs}, defs);
renderToHtml(Template, {configs}, 1, defs);
expect(objectComps[0].config).toEqual({opacity: 0, duration: 1000});
expect(objectComps[1].config).toEqual({opacity: 1, duration: 600});
});

View File

@ -77,7 +77,7 @@ describe('query', () => {
child2 = loadDirective(1);
}
},
[Child], [],
2, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, Child, false);
@ -115,7 +115,7 @@ describe('query', () => {
elToQuery = loadElement(1).native;
}
},
[Child], [],
1, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, Child, false, QUERY_READ_ELEMENT_REF);
@ -152,7 +152,7 @@ describe('query', () => {
elementEnd();
}
},
[Child, OtherChild], [],
1, [Child, OtherChild], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, Child, false, OtherChild);
@ -185,7 +185,7 @@ describe('query', () => {
element(1, 'div', ['child', '']);
}
},
[Child, OtherChild], [],
1, [Child, OtherChild], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, Child, false, OtherChild);
@ -223,7 +223,7 @@ describe('query', () => {
element(3, 'div');
}
},
[], [],
3, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_FROM_NODE);
@ -260,7 +260,7 @@ describe('query', () => {
element(5, 'div');
}
},
[], [],
4, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_FROM_NODE);
@ -309,7 +309,7 @@ describe('query', () => {
el2ToQuery = loadElement(4).native;
}
},
[], [],
5, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE);
@ -346,7 +346,7 @@ describe('query', () => {
element(3, 'div');
}
},
[], [],
3, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_ELEMENT_REF);
@ -382,7 +382,7 @@ describe('query', () => {
elementContainerEnd();
}
},
[], [],
2, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_ELEMENT_REF);
@ -447,7 +447,7 @@ describe('query', () => {
elementContainerEnd();
}
},
[], [],
3, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_ELEMENT_REF);
@ -482,7 +482,7 @@ describe('query', () => {
element(1, 'div', null, ['foo', '']);
}
},
[], [],
2, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_CONTAINER_REF);
@ -510,10 +510,10 @@ describe('query', () => {
'cmpt',
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(1, null, null, null, ['foo', '']);
template(1, null, 0, null, null, ['foo', '']);
}
},
[], [],
2, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_CONTAINER_REF);
@ -542,10 +542,10 @@ describe('query', () => {
'cmpt',
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(1, null, null, null, ['foo', '']);
template(1, null, 0, null, null, ['foo', '']);
}
},
[], [],
2, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
@ -577,10 +577,10 @@ describe('query', () => {
'cmpt',
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(1, null, null, null, ['foo', '']);
template(1, null, 0, null, null, ['foo', '']);
}
},
[], [],
2, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], undefined, QUERY_READ_FROM_NODE);
@ -609,10 +609,10 @@ describe('query', () => {
'cmpt',
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(1, null, null, null, ['foo', '']);
template(1, null, 0, null, null, ['foo', '']);
}
},
[], [],
2, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_TEMPLATE_REF);
@ -649,7 +649,7 @@ describe('query', () => {
childInstance = loadDirective(0);
}
},
[Child], [],
2, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
@ -674,6 +674,7 @@ describe('query', () => {
type: Child,
selectors: [['child']],
factory: () => childInstance = new Child(),
consts: 0,
template: (rf: RenderFlags, ctx: Child) => {},
exportAs: 'child'
});
@ -692,7 +693,7 @@ describe('query', () => {
element(1, 'child', null, ['foo', 'child']);
}
},
[Child], [],
2, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
@ -730,7 +731,7 @@ describe('query', () => {
childInstance = loadDirective(0);
}
},
[Child], [],
2, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
@ -770,7 +771,7 @@ describe('query', () => {
child2Instance = loadDirective(1);
}
},
[Child1, Child2], [],
3, [Child1, Child2], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo', 'bar'], true, QUERY_READ_FROM_NODE);
@ -809,7 +810,7 @@ describe('query', () => {
childInstance = loadDirective(0);
}
},
[Child], [],
3, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
@ -853,7 +854,7 @@ describe('query', () => {
div = loadElement(1).native;
}
},
[Child], [],
2, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], undefined, QUERY_READ_ELEMENT_REF);
@ -891,7 +892,7 @@ describe('query', () => {
childInstance = loadDirective(0);
}
},
[Child], [],
3, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE);
@ -925,7 +926,7 @@ describe('query', () => {
element(1, 'div', ['foo', '']);
}
},
[Child], [],
2, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, Child);
@ -975,6 +976,12 @@ describe('query', () => {
it('should report results in views inserted / removed by ngIf', () => {
function Cmpt_Template_1(rf: RenderFlags, ctx1: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
}
}
/**
* <ng-template [ngIf]="value">
* <div #foo></div>
@ -987,17 +994,13 @@ describe('query', () => {
'cmpt',
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(1, (rf1: RenderFlags, ctx1: any) => {
if (rf1 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
}
}, null, ['ngIf', '']);
template(1, Cmpt_Template_1, 2, null, ['ngIf', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(1, 'ngIf', bind(ctx.value));
}
},
[NgIf], [],
2, [NgIf], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
@ -1023,6 +1026,15 @@ describe('query', () => {
it('should report results in views inserted / removed by ngFor', () => {
function Cmpt_Template_1(rf1: RenderFlags, row: NgForOfContext<string>) {
if (rf1 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
}
if (rf1 & RenderFlags.Update) {
elementProperty(0, 'id', bind(row.$implicit));
}
}
/**
* <ng-template ngFor let-item [ngForOf]="value">
* <div #foo [id]="item"></div>
@ -1039,16 +1051,10 @@ describe('query', () => {
type: Cmpt,
factory: () => new Cmpt(),
selectors: [['my-app']],
consts: 2,
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(1, (rf1: RenderFlags, row: NgForOfContext<string>) => {
if (rf1 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
}
if (rf1 & RenderFlags.Update) {
elementProperty(0, 'id', bind(row.$implicit));
}
}, null, ['ngForOf', '']);
template(1, Cmpt_Template_1, 2, null, ['ngForOf', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(1, 'ngForOf', bind(ctx.value));
@ -1091,6 +1097,23 @@ describe('query', () => {
let tpl1: TemplateRef<{}>;
let tpl2: TemplateRef<{}>;
function Cmpt_Template_1(rf: RenderFlags, ctx: {idx: number}) {
if (rf & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind('foo1_' + ctx.idx));
}
}
function Cmpt_Template_5(rf: RenderFlags, ctx: {idx: number}) {
if (rf & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind('foo2_' + ctx.idx));
}
}
/**
* <ng-template #tpl1 let-idx="idx">
@ -1109,27 +1132,10 @@ describe('query', () => {
'cmpt',
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(1, (rf: RenderFlags, ctx: {idx: number}) => {
if (rf & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind('foo1_' + ctx.idx));
}
}, null, null, ['tpl1', ''], templateRefExtractor);
template(1, Cmpt_Template_1, 2, null, null, ['tpl1', ''], templateRefExtractor);
element(3, 'div', ['id', 'middle'], ['foo', '']);
template(5, (rf: RenderFlags, ctx: {idx: number}) => {
if (rf & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind('foo2_' + ctx.idx));
}
}, null, null, ['tpl2', ''], templateRefExtractor);
template(7, null, null, [AttributeMarker.SelectOnly, 'vc']);
template(5, Cmpt_Template_5, 2, null, null, ['tpl2', ''], templateRefExtractor);
template(7, null, 0, null, [AttributeMarker.SelectOnly, 'vc']);
}
if (rf & RenderFlags.Update) {
@ -1138,7 +1144,7 @@ describe('query', () => {
}
},
[ViewContainerManipulatorDirective], [],
6, [ViewContainerManipulatorDirective], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
@ -1195,6 +1201,15 @@ describe('query', () => {
() => {
let tpl: TemplateRef<{}>;
function Cmpt_Template_1(rf: RenderFlags, ctx: {idx: number, container_idx: number}) {
if (rf & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind('foo_' + ctx.container_idx + '_' + ctx.idx));
}
}
/**
* <ng-template #tpl let-idx="idx" let-container_idx="container_idx">
* <div #foo [id]="'foo_'+container_idx+'_'+idx"></div>
@ -1209,20 +1224,13 @@ describe('query', () => {
type: Cmpt,
factory: () => new Cmpt(),
selectors: [['my-app']],
consts: 4,
template: function(rf: RenderFlags, ctx: any) {
let tmp: any;
if (rf & RenderFlags.Create) {
template(1, (rf: RenderFlags, ctx: {idx: number, container_idx: number}) => {
if (rf & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind('foo_' + ctx.container_idx + '_' + ctx.idx));
}
}, null, [], ['tpl', ''], templateRefExtractor);
template(3, null, null, [AttributeMarker.SelectOnly, 'vc']);
template(4, null, null, [AttributeMarker.SelectOnly, 'vc']);
template(1, Cmpt_Template_1, 2, null, [], ['tpl', ''], templateRefExtractor);
template(3, null, 0, null, [AttributeMarker.SelectOnly, 'vc']);
template(4, null, 0, null, [AttributeMarker.SelectOnly, 'vc']);
}
if (rf & RenderFlags.Update) {
@ -1270,6 +1278,12 @@ describe('query', () => {
// https://stackblitz.com/edit/angular-wpd6gv?file=src%2Fapp%2Fapp.component.ts
it('should report results from views inserted in a lifecycle hook', () => {
function MyApp_Template_1(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'span', ['id', 'from_tpl'], ['foo', '']);
}
}
class MyApp {
show = false;
query: any;
@ -1277,18 +1291,17 @@ describe('query', () => {
type: MyApp,
factory: () => new MyApp(),
selectors: [['my-app']],
consts: 4,
/**
* <ng-template #tpl><span #foo id="from_tpl">from tpl</span></ng-template>
* <ng-template #tpl><span #foo id="from_tpl"></span></ng-template>
* <ng-template [ngTemplateOutlet]="show ? tpl : null"></ng-template>
*/
template: (rf: RenderFlags, myApp: MyApp) => {
if (rf & RenderFlags.Create) {
template(1, (rf1: RenderFlags) => {
if (rf1 & RenderFlags.Create) {
element(0, 'span', ['id', 'from_tpl'], ['foo', '']);
}
}, undefined, undefined, ['tpl', ''], templateRefExtractor);
template(3, null, null, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']);
template(
1, MyApp_Template_1, 2, undefined, undefined, ['tpl', ''],
templateRefExtractor);
template(3, null, 0, null, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']);
}
if (rf & RenderFlags.Update) {
const tplRef = reference(2);
@ -1348,7 +1361,7 @@ describe('query', () => {
containerRefreshStart(1);
{
if (ctx.exp) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 2);
{
if (rf1 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
@ -1361,7 +1374,7 @@ describe('query', () => {
containerRefreshEnd();
}
},
[], [],
1, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
@ -1413,7 +1426,7 @@ describe('query', () => {
containerRefreshStart(3);
{
if (ctx.exp) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 2);
{
if (rf1 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
@ -1426,7 +1439,7 @@ describe('query', () => {
containerRefreshEnd();
}
},
[], [],
5, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
@ -1480,7 +1493,7 @@ describe('query', () => {
containerRefreshStart(1);
{
if (ctx.exp1) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 2);
{
if (rf0 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
@ -1490,7 +1503,7 @@ describe('query', () => {
embeddedViewEnd();
}
if (ctx.exp2) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 2);
{
if (rf1 & RenderFlags.Create) {
element(0, 'span', null, ['foo', '']);
@ -1503,7 +1516,7 @@ describe('query', () => {
containerRefreshEnd();
}
},
[], [],
1, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
@ -1553,7 +1566,7 @@ describe('query', () => {
containerRefreshStart(1);
{
if (ctx.exp1) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 3);
{
if (rf0 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
@ -1564,7 +1577,7 @@ describe('query', () => {
containerRefreshStart(2);
{
if (ctx.exp2) {
let rf2 = embeddedViewStart(0);
let rf2 = embeddedViewStart(0, 2);
{
if (rf2) {
element(0, 'span', null, ['foo', '']);
@ -1583,7 +1596,7 @@ describe('query', () => {
containerRefreshEnd();
}
},
[], [],
1, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
@ -1638,7 +1651,7 @@ describe('query', () => {
containerRefreshStart(2);
{
if (ctx.exp) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 4);
{
if (rf0 & RenderFlags.Create) {
elementStart(0, 'div', null, ['foo', '']);
@ -1652,7 +1665,7 @@ describe('query', () => {
containerRefreshEnd();
}
},
[], [],
3, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
@ -1733,7 +1746,7 @@ describe('query', () => {
element(1, 'div', null, ['foo', '']);
}
},
[], [],
1, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_FROM_NODE);
@ -1751,7 +1764,7 @@ describe('query', () => {
containerRefreshStart(0);
{
if (condition) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 1);
{
if (rf1 & RenderFlags.Create) {
element(0, 'some-component-with-query');
@ -1769,7 +1782,7 @@ describe('query', () => {
* %}
*/
let condition = true;
const t = new TemplateFixture(createTemplate, updateTemplate, [SimpleComponentWithQuery]);
const t = new TemplateFixture(createTemplate, updateTemplate, 1, [SimpleComponentWithQuery]);
expect(t.html).toEqual('<some-component-with-query><div></div></some-component-with-query>');
expect((queryInstance !.changes as EventEmitter<any>).closed).toBeFalsy();
@ -1807,11 +1820,11 @@ describe('query', () => {
'app',
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(1, AppComponent_Template_1, null, [AttributeMarker.SelectOnly, 'someDir']);
template(1, AppComponent_Template_1, 1, null, [AttributeMarker.SelectOnly, 'someDir']);
element(2, 'div', null, ['foo', '']);
}
},
[SomeDir], [],
3, [SomeDir], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
@ -1871,6 +1884,7 @@ describe('query', () => {
selectors: [['shallow-comp']],
factory: () => new ShallowComp(),
template: function(rf: RenderFlags, ctx: any) {},
consts: 0,
contentQueries:
() => { registerContentQuery(query(null, ['foo'], false, QUERY_READ_FROM_NODE)); },
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
@ -1894,7 +1908,7 @@ describe('query', () => {
{ element(1, 'span', null, ['foo', '']); }
elementEnd();
}
}, [WithContentDirective]);
}, 3, [WithContentDirective]);
const fixture = new ComponentFixture(AppComponent);
expect(withContentInstance !.foos.length)
@ -1920,7 +1934,7 @@ describe('query', () => {
if (rf & RenderFlags.Create) {
element(0, 'div', ['with-content', ''], ['foo', '']);
}
}, [WithContentDirective]);
}, 2, [WithContentDirective]);
const fixture = new ComponentFixture(AppComponent);
expect(withContentInstance !.foos.length)
@ -1942,13 +1956,13 @@ describe('query', () => {
const AppComponent = createComponent('app-component', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'shallow-comp');
{ template(1, IfTemplate, null, [AttributeMarker.SelectOnly, 'ngIf', '']); }
{ template(1, IfTemplate, 2, null, [AttributeMarker.SelectOnly, 'ngIf', '']); }
elementEnd();
}
if (rf & RenderFlags.Update) {
elementProperty(1, 'ngIf', bind(ctx.showing));
}
}, [ShallowComp, NgIf]);
}, 2, [ShallowComp, NgIf]);
const fixture = new ComponentFixture(AppComponent);
const qList = shallowCompInstance !.foos;
@ -1985,7 +1999,7 @@ describe('query', () => {
element(4, 'div', ['id', 'after'], ['bar', '']);
}
},
[WithContentDirective], [],
5, [WithContentDirective], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo', 'bar'], true, QUERY_READ_FROM_NODE);
@ -2025,7 +2039,7 @@ describe('query', () => {
element(4, 'div', null, ['foo', '']);
}
},
[WithContentDirective], [],
5, [WithContentDirective], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['bar'], true, QUERY_READ_FROM_NODE);
@ -2094,7 +2108,7 @@ describe('query', () => {
inInstance = load<QueryDirective>(5);
}
},
[QueryDirective]);
10, [QueryDirective]);
const fixture = new ComponentFixture(AppComponent);
expect(outInstance !.fooBars.length).toBe(3);
@ -2151,7 +2165,7 @@ describe('query', () => {
inInstance = load<QueryDirective>(3);
}
},
[QueryDirective]);
7, [QueryDirective]);
const fixture = new ComponentFixture(AppComponent);
expect(outInstance !.fooBars.length).toBe(1);
@ -2231,7 +2245,7 @@ describe('query', () => {
deepInstance = load<DeepQueryDirective>(2);
}
},
[ShallowQueryDirective, DeepQueryDirective]);
8, [ShallowQueryDirective, DeepQueryDirective]);
const fixture = new ComponentFixture(AppComponent);
expect(shallowInstance !.foos.length).toBe(1);

View File

@ -59,7 +59,7 @@ export class TemplateFixture extends BaseFixture {
* `if (rf & RenderFlags.Update) { __here__ }`.
*/
constructor(
private createBlock: () => void, private updateBlock: () => void = noop,
private createBlock: () => void, private updateBlock: () => void = noop, consts: number = 0,
directives?: DirectiveTypesOrFactory|null, pipes?: PipeTypesOrFactory|null,
sanitizer?: Sanitizer|null, rendererFactory?: RendererFactory3) {
super();
@ -74,7 +74,7 @@ export class TemplateFixture extends BaseFixture {
if (rf & RenderFlags.Update) {
this.updateBlock();
}
}, null !, this._rendererFactory, null, this._directiveDefs, this._pipeDefs, sanitizer);
}, consts, null !, this._rendererFactory, null, this._directiveDefs, this._pipeDefs, sanitizer);
}
/**
@ -84,7 +84,7 @@ export class TemplateFixture extends BaseFixture {
*/
update(updateBlock?: () => void): void {
renderTemplate(
this.hostNode.native, updateBlock || this.updateBlock, null !, this._rendererFactory,
this.hostNode.native, updateBlock || this.updateBlock, 0, null !, this._rendererFactory,
this.hostNode, this._directiveDefs, this._pipeDefs, this._sanitizer);
}
}
@ -170,10 +170,11 @@ export function resetDOM() {
* @deprecated use `TemplateFixture` or `ComponentFixture`
*/
export function renderToHtml(
template: ComponentTemplate<any>, ctx: any, directives?: DirectiveTypesOrFactory | null,
pipes?: PipeTypesOrFactory | null, providedRendererFactory?: RendererFactory3 | null) {
template: ComponentTemplate<any>, ctx: any, consts: number = 0,
directives?: DirectiveTypesOrFactory | null, pipes?: PipeTypesOrFactory | null,
providedRendererFactory?: RendererFactory3 | null) {
host = renderTemplate(
containerEl, template, ctx, providedRendererFactory || testRendererFactory, host,
containerEl, template, consts, ctx, providedRendererFactory || testRendererFactory, host,
toDefs(directives, extractDirectiveDef), toDefs(pipes, extractPipeDef));
return toHtml(containerEl);
}
@ -228,14 +229,15 @@ export function toHtml<T>(componentOrElement: T | RElement): string {
}
export function createComponent(
name: string, template: ComponentTemplate<any>, directives: DirectiveTypesOrFactory = [],
pipes: PipeTypesOrFactory = [],
name: string, template: ComponentTemplate<any>, consts: number = 0,
directives: DirectiveTypesOrFactory = [], pipes: PipeTypesOrFactory = [],
viewQuery: ComponentTemplate<any>| null = null): ComponentType<any> {
return class Component {
value: any;
static ngComponentDef = defineComponent({
type: Component,
selectors: [[name]],
consts: consts,
factory: () => new Component,
template: template,
viewQuery: viewQuery,

View File

@ -33,6 +33,7 @@ describe('renderer factory lifecycle', () => {
static ngComponentDef = defineComponent({
type: SomeComponent,
selectors: [['some-component']],
consts: 1,
template: function(rf: RenderFlags, ctx: SomeComponent) {
logs.push('component');
if (rf & RenderFlags.Create) {
@ -47,6 +48,7 @@ describe('renderer factory lifecycle', () => {
static ngComponentDef = defineComponent({
type: SomeComponentWhichThrows,
selectors: [['some-component-with-Error']],
consts: 0,
template: function(rf: RenderFlags, ctx: SomeComponentWhichThrows) {
throw(new Error('SomeComponentWhichThrows threw'));
},
@ -88,7 +90,7 @@ describe('renderer factory lifecycle', () => {
});
it('should work with a template', () => {
renderToHtml(Template, {}, null, null, rendererFactory);
renderToHtml(Template, {}, 1, null, null, rendererFactory);
expect(logs).toEqual(['create', 'begin', 'function', 'end']);
logs = [];
@ -97,12 +99,12 @@ describe('renderer factory lifecycle', () => {
});
it('should work with a template which contains a component', () => {
renderToHtml(TemplateWithComponent, {}, directives, null, rendererFactory);
renderToHtml(TemplateWithComponent, {}, 2, directives, null, rendererFactory);
expect(logs).toEqual(
['create', 'begin', 'function_with_component', 'create', 'component', 'end']);
logs = [];
renderToHtml(TemplateWithComponent, {}, directives);
renderToHtml(TemplateWithComponent, {}, 2, directives);
expect(logs).toEqual(['begin', 'function_with_component', 'component', 'end']);
});
@ -125,6 +127,7 @@ describe('animation renderer factory', () => {
static ngComponentDef = defineComponent({
type: SomeComponent,
selectors: [['some-component']],
consts: 1,
template: function(rf: RenderFlags, ctx: SomeComponent) {
if (rf & RenderFlags.Create) {
text(0, 'foo');
@ -143,6 +146,7 @@ describe('animation renderer factory', () => {
static ngComponentDef = defineComponent({
type: SomeComponentWithAnimation,
selectors: [['some-component']],
consts: 2,
template: function(rf: RenderFlags, ctx: SomeComponentWithAnimation) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
@ -221,7 +225,7 @@ describe('Renderer2 destruction hooks', () => {
containerRefreshStart(1);
{
if (condition) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 3);
{
if (rf1 & RenderFlags.Create) {
element(0, 'span');
@ -236,7 +240,7 @@ describe('Renderer2 destruction hooks', () => {
}
const t =
new TemplateFixture(createTemplate, updateTemplate, null, null, null, rendererFactory);
new TemplateFixture(createTemplate, updateTemplate, 2, null, null, null, rendererFactory);
expect(t.html).toEqual('<div><span></span><span></span><span></span></div>');
@ -251,6 +255,7 @@ describe('Renderer2 destruction hooks', () => {
static ngComponentDef = defineComponent({
type: SimpleComponent,
selectors: [['simple']],
consts: 1,
template: function(rf: RenderFlags, ctx: SimpleComponent) {
if (rf & RenderFlags.Create) {
element(0, 'span');
@ -272,7 +277,7 @@ describe('Renderer2 destruction hooks', () => {
containerRefreshStart(1);
{
if (condition) {
let rf1 = embeddedViewStart(1);
let rf1 = embeddedViewStart(1, 3);
{
if (rf1 & RenderFlags.Create) {
element(0, 'simple');
@ -287,7 +292,7 @@ describe('Renderer2 destruction hooks', () => {
}
const t = new TemplateFixture(
createTemplate, updateTemplate, [SimpleComponent], null, null, rendererFactory);
createTemplate, updateTemplate, 2, [SimpleComponent], null, null, rendererFactory);
expect(t.html).toEqual(
'<div><simple><span></span></simple><span></span><simple><span></span></simple></div>');

View File

@ -28,6 +28,7 @@ describe('ViewContainerRef', () => {
type: DirectiveWithVCRef,
selectors: [['', 'vcref', '']],
factory: () => directiveInstance = new DirectiveWithVCRef(
injectViewContainerRef(), injectComponentFactoryResolver()),
inputs: {tplRef: 'tplRef'}
});
@ -63,7 +64,7 @@ describe('ViewContainerRef', () => {
* <p vcref [tplRef]="tplRef"></p>
*/
function createTemplate() {
template(0, embeddedTemplate, null, null, ['tplRef', ''], templateRefExtractor);
template(0, embeddedTemplate, 1, null, null, ['tplRef', ''], templateRefExtractor);
element(2, 'p', ['vcref', '']);
}
@ -80,12 +81,13 @@ describe('ViewContainerRef', () => {
* <footer></footer>
*/
function createTemplate() {
template(0, embeddedTemplate, null, null, ['tplRef', ''], templateRefExtractor);
template(0, embeddedTemplate, 1, null, null, ['tplRef', ''], templateRefExtractor);
element(2, 'header', ['vcref', '']);
element(3, 'footer');
}
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
const fixture =
new TemplateFixture(createTemplate, updateTemplate, 4, [DirectiveWithVCRef]);
expect(fixture.html).toEqual('<header vcref=""></header><footer></footer>');
createView('A');
@ -115,13 +117,13 @@ describe('ViewContainerRef', () => {
* <footer></footer>
*/
function createTemplate() {
template(0, embeddedTemplate, null, [], ['tplRef', ''], templateRefExtractor);
template(0, embeddedTemplate, 1, null, [], ['tplRef', ''], templateRefExtractor);
element(2, 'header-cmp', ['vcref', '']);
element(3, 'footer');
}
const fixture = new TemplateFixture(
createTemplate, updateTemplate, [HeaderComponent, DirectiveWithVCRef]);
createTemplate, updateTemplate, 3, [HeaderComponent, DirectiveWithVCRef]);
expect(fixture.html).toEqual('<header-cmp vcref=""></header-cmp><footer></footer>');
createView('A');
@ -151,7 +153,7 @@ describe('ViewContainerRef', () => {
* <div vcref [tplRef]="tplRef"></div>
*/
function createTemplate() {
template(0, embeddedTemplate, null, null, ['tplRef', ''], templateRefExtractor);
template(0, embeddedTemplate, 1, null, null, ['tplRef', ''], templateRefExtractor);
element(2, 'div', ['vcref', '']);
element(3, 'div', ['vcref', '']);
@ -166,7 +168,7 @@ describe('ViewContainerRef', () => {
elementProperty(3, 'tplRef', bind(tplRef));
}
const fixture = new TemplateFixture(createTemplate, update, [DirectiveWithVCRef]);
const fixture = new TemplateFixture(createTemplate, update, 4, [DirectiveWithVCRef]);
expect(fixture.html).toEqual('<div vcref=""></div><div vcref=""></div>');
firstDir !.vcref.createEmbeddedView(firstDir !.tplRef, {name: 'A'});
@ -181,7 +183,8 @@ describe('ViewContainerRef', () => {
* <footer></footer>
*/
function createTemplate() {
template(0, embeddedTemplate, null, ['vcref', ''], ['tplRef', ''], templateRefExtractor);
template(
0, embeddedTemplate, 1, null, ['vcref', ''], ['tplRef', ''], templateRefExtractor);
element(2, 'footer');
}
@ -190,7 +193,8 @@ describe('ViewContainerRef', () => {
elementProperty(0, 'tplRef', bind(tplRef));
}
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
const fixture =
new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]);
expect(fixture.html).toEqual('<footer></footer>');
createView('A');
@ -259,11 +263,12 @@ describe('ViewContainerRef', () => {
type: TestComponent,
selectors: [['test-cmp']],
factory: () => new TestComponent(),
consts: 4,
template: (rf: RenderFlags, cmp: TestComponent) => {
if (rf & RenderFlags.Create) {
text(0, 'before|');
template(1, EmbeddedTemplateA, null, ['testdir', '']);
template(2, EmbeddedTemplateB, null, ['testdir', '']);
template(1, EmbeddedTemplateA, 1, null, ['testdir', '']);
template(2, EmbeddedTemplateB, 1, null, ['testdir', '']);
text(3, '|after');
}
},
@ -327,11 +332,12 @@ describe('ViewContainerRef', () => {
static ngComponentDef = defineComponent({
type: TestComponent,
selectors: [['test-cmp']],
consts: 4,
factory: () => new TestComponent(),
template: (rf: RenderFlags, cmp: TestComponent) => {
if (rf & RenderFlags.Create) {
text(0, 'before|');
template(1, EmbeddedTemplateA, null, ['testdir', '']);
template(1, EmbeddedTemplateA, 1, null, ['testdir', '']);
container(2);
text(3, '|after');
}
@ -339,7 +345,7 @@ describe('ViewContainerRef', () => {
containerRefreshStart(2);
{
if (cmp.condition) {
let rf1 = embeddedViewStart(0);
let rf1 = embeddedViewStart(0, 1);
{
if (rf1 & RenderFlags.Create) {
text(0, 'B');
@ -387,6 +393,7 @@ describe('ViewContainerRef', () => {
type: Child,
selectors: [['child']],
factory: () => new Child(),
consts: 1,
template: (rf: RenderFlags, cmp: Child) => {
if (rf & RenderFlags.Create) {
text(0);
@ -434,9 +441,11 @@ describe('ViewContainerRef', () => {
type: SomeComponent,
selectors: [['some-comp']],
factory: () => new SomeComponent(),
consts: 6,
template: (rf: RenderFlags, cmp: SomeComponent) => {
if (rf & RenderFlags.Create) {
template(0, SomeComponent_Template_0, null, [], ['foo', ''], templateRefExtractor);
template(
0, SomeComponent_Template_0, 2, null, [], ['foo', ''], templateRefExtractor);
pipe(2, 'starPipe');
element(3, 'child', ['vcref', '']);
pipe(4, 'starPipe');
@ -498,6 +507,7 @@ describe('ViewContainerRef', () => {
type: Child,
selectors: [['child']],
factory: () => child = new Child(),
consts: 2,
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', [AttributeMarker.SelectOnly, 'tplDir']);
@ -524,7 +534,7 @@ describe('ViewContainerRef', () => {
*/
const Parent = createComponent('parent', function(rf: RenderFlags, parent: any) {
if (rf & RenderFlags.Create) {
template(0, fooTemplate, null, null, ['foo', ''], templateRefExtractor);
template(0, fooTemplate, 2, null, null, ['foo', ''], templateRefExtractor);
element(2, 'child');
}
@ -533,7 +543,7 @@ describe('ViewContainerRef', () => {
elementProperty(2, 'tpl', bind(tplRef));
}
}, [Child]);
}, 3, [Child]);
function fooTemplate(rf1: RenderFlags, ctx: any) {
if (rf1 & RenderFlags.Create) {
@ -581,9 +591,10 @@ describe('ViewContainerRef', () => {
type: LoopComp,
selectors: [['loop-comp']],
factory: () => new LoopComp(),
consts: 1,
template: function(rf: RenderFlags, loop: any) {
if (rf & RenderFlags.Create) {
template(0, () => {}, null, [AttributeMarker.SelectOnly, 'ngForOf']);
template(0, null, 0, null, [AttributeMarker.SelectOnly, 'ngForOf']);
}
if (rf & RenderFlags.Update) {
@ -613,7 +624,7 @@ describe('ViewContainerRef', () => {
*/
const Parent = createComponent('parent', function(rf: RenderFlags, parent: any) {
if (rf & RenderFlags.Create) {
template(0, rowTemplate, null, null, ['rowTemplate', ''], templateRefExtractor);
template(0, rowTemplate, 3, null, null, ['rowTemplate', ''], templateRefExtractor);
element(2, 'loop-comp');
}
@ -623,11 +634,11 @@ describe('ViewContainerRef', () => {
elementProperty(2, 'rows', bind(parent.rows));
}
}, [LoopComp]);
}, 3, [LoopComp]);
function rowTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(0, cellTemplate, null, null, ['cellTemplate', ''], templateRefExtractor);
template(0, cellTemplate, 2, null, null, ['cellTemplate', ''], templateRefExtractor);
element(2, 'loop-comp');
}
@ -685,7 +696,7 @@ describe('ViewContainerRef', () => {
describe('detach', () => {
it('should detach the right embedded view when an index is specified', () => {
const fixture = new TemplateFixture(
createTemplate, updateTemplate, [DirectiveWithVCRef], null, null, rendererFactory);
createTemplate, updateTemplate, 3, [DirectiveWithVCRef], null, null, rendererFactory);
const viewA = createView('A');
createView('B');
createView('C');
@ -712,7 +723,7 @@ describe('ViewContainerRef', () => {
it('should detach the last embedded view when no index is specified', () => {
const fixture = new TemplateFixture(
createTemplate, updateTemplate, [DirectiveWithVCRef], null, null, rendererFactory);
createTemplate, updateTemplate, 3, [DirectiveWithVCRef], null, null, rendererFactory);
createView('A');
createView('B');
createView('C');
@ -732,7 +743,7 @@ describe('ViewContainerRef', () => {
describe('remove', () => {
it('should remove the right embedded view when an index is specified', () => {
const fixture = new TemplateFixture(
createTemplate, updateTemplate, [DirectiveWithVCRef], null, null, rendererFactory);
createTemplate, updateTemplate, 3, [DirectiveWithVCRef], null, null, rendererFactory);
const viewA = createView('A');
createView('B');
createView('C');
@ -758,7 +769,7 @@ describe('ViewContainerRef', () => {
it('should remove the last embedded view when no index is specified', () => {
const fixture = new TemplateFixture(
createTemplate, updateTemplate, [DirectiveWithVCRef], null, null, rendererFactory);
createTemplate, updateTemplate, 3, [DirectiveWithVCRef], null, null, rendererFactory);
createView('A');
createView('B');
createView('C');
@ -776,7 +787,7 @@ describe('ViewContainerRef', () => {
it('should throw when trying to insert a removed or destroyed view', () => {
const fixture = new TemplateFixture(
createTemplate, updateTemplate, [DirectiveWithVCRef], null, null, rendererFactory);
createTemplate, updateTemplate, 3, [DirectiveWithVCRef], null, null, rendererFactory);
const viewA = createView('A');
const viewB = createView('B');
fixture.update();
@ -793,7 +804,8 @@ describe('ViewContainerRef', () => {
describe('length', () => {
it('should return the number of embedded views', () => {
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
const fixture =
new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]);
expect(directiveInstance !.vcref.length).toEqual(0);
createView('A');
@ -814,7 +826,8 @@ describe('ViewContainerRef', () => {
describe('get and indexOf', () => {
it('should retrieve a ViewRef from its index, and vice versa', () => {
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
const fixture =
new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]);
createView('A');
createView('B');
createView('C');
@ -831,7 +844,8 @@ describe('ViewContainerRef', () => {
});
it('should handle out of bounds cases', () => {
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
const fixture =
new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]);
createView('A');
fixture.update();
@ -846,7 +860,8 @@ describe('ViewContainerRef', () => {
describe('move', () => {
it('should move embedded views and associated DOM nodes without recreating them', () => {
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
const fixture =
new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]);
createView('A');
createView('B');
createView('C');
@ -883,6 +898,7 @@ describe('ViewContainerRef', () => {
type: EmbeddedComponent,
selectors: [['embedded-cmp']],
factory: () => new EmbeddedComponent(),
consts: 1,
template: (rf: RenderFlags, cmp: EmbeddedComponent) => {
templateExecutionCounter++;
if (rf & RenderFlags.Create) {
@ -894,7 +910,8 @@ describe('ViewContainerRef', () => {
it('should work without Injector and NgModuleRef', () => {
templateExecutionCounter = 0;
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
const fixture =
new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]);
expect(fixture.html).toEqual('<p vcref=""></p>');
expect(templateExecutionCounter).toEqual(0);
@ -939,7 +956,8 @@ describe('ViewContainerRef', () => {
const injector = createInjector(SomeModule);
templateExecutionCounter = 0;
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
const fixture =
new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]);
expect(fixture.html).toEqual('<p vcref=""></p>');
expect(templateExecutionCounter).toEqual(0);
@ -964,6 +982,7 @@ describe('ViewContainerRef', () => {
type: EmbeddedComponentWithNgContent,
selectors: [['embedded-cmp-with-ngcontent']],
factory: () => new EmbeddedComponentWithNgContent(),
consts: 3,
template: (rf: RenderFlags, cmp: EmbeddedComponentWithNgContent) => {
if (rf & RenderFlags.Create) {
projectionDef();
@ -976,7 +995,8 @@ describe('ViewContainerRef', () => {
}
it('should support projectable nodes', () => {
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
const fixture =
new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]);
expect(fixture.html).toEqual('<p vcref=""></p>');
const myNode = document.createElement('div');
@ -1000,6 +1020,7 @@ describe('ViewContainerRef', () => {
type: Reprojector,
selectors: [['reprojector']],
factory: () => new Reprojector(),
consts: 2,
template: (rf: RenderFlags, cmp: Reprojector) => {
if (rf & RenderFlags.Create) {
projectionDef();
@ -1012,7 +1033,8 @@ describe('ViewContainerRef', () => {
});
}
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
const fixture =
new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]);
expect(fixture.html).toEqual('<p vcref=""></p>');
const myNode = document.createElement('div');
@ -1030,7 +1052,8 @@ describe('ViewContainerRef', () => {
});
it('should support many projectable nodes with many slots', () => {
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
const fixture =
new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]);
expect(fixture.html).toEqual('<p vcref=""></p>');
directiveInstance !.vcref.createComponent(
@ -1053,7 +1076,7 @@ describe('ViewContainerRef', () => {
element(1, 'footer');
}
new TemplateFixture(createTemplate, undefined, [DirectiveWithVCRef]);
new TemplateFixture(createTemplate, undefined, 2, [DirectiveWithVCRef]);
expect(directiveInstance !.vcref.element.nativeElement.tagName.toLowerCase())
.toEqual('header');
@ -1072,7 +1095,7 @@ describe('ViewContainerRef', () => {
element(1, 'footer');
}
new TemplateFixture(createTemplate, undefined, [HeaderComponent, DirectiveWithVCRef]);
new TemplateFixture(createTemplate, undefined, 2, [HeaderComponent, DirectiveWithVCRef]);
expect(directiveInstance !.vcref.element.nativeElement.tagName.toLowerCase())
.toEqual('header-cmp');
@ -1084,11 +1107,11 @@ describe('ViewContainerRef', () => {
it('should work on templates', () => {
function createTemplate() {
template(0, embeddedTemplate, null, ['vcref', '']);
template(0, embeddedTemplate, 1, null, ['vcref', '']);
element(1, 'footer');
}
new TemplateFixture(createTemplate, () => {}, [DirectiveWithVCRef]);
new TemplateFixture(createTemplate, () => {}, 2, [DirectiveWithVCRef]);
expect(directiveInstance !.vcref.element.nativeElement.textContent).toEqual('container');
expect(directiveInstance !.vcref.injector.get(ElementRef).nativeElement.textContent)
.toEqual('container');
@ -1114,6 +1137,7 @@ describe('ViewContainerRef', () => {
type: Child,
selectors: [['child']],
factory: () => new Child(),
consts: 2,
template: (rf: RenderFlags, cmp: Child) => {
if (rf & RenderFlags.Create) {
projectionDef();
@ -1139,9 +1163,10 @@ describe('ViewContainerRef', () => {
type: Parent,
selectors: [['parent']],
factory: () => new Parent(),
consts: 5,
template: (rf: RenderFlags, cmp: Parent) => {
if (rf & RenderFlags.Create) {
template(0, embeddedTemplate, null, null, ['foo', ''], templateRefExtractor);
template(0, embeddedTemplate, 2, null, null, ['foo', ''], templateRefExtractor);
elementStart(2, 'child');
{
elementStart(3, 'header', ['vcref', '']);
@ -1187,6 +1212,7 @@ describe('ViewContainerRef', () => {
type: ChildWithView,
selectors: [['child-with-view']],
factory: () => new ChildWithView(),
consts: 3,
template: (rf: RenderFlags, cmp: ChildWithView) => {
if (rf & RenderFlags.Create) {
projectionDef();
@ -1197,7 +1223,7 @@ describe('ViewContainerRef', () => {
if (rf & RenderFlags.Update) {
containerRefreshStart(1);
if (cmp.show) {
let rf0 = embeddedViewStart(0);
let rf0 = embeddedViewStart(0, 1);
if (rf0 & RenderFlags.Create) {
projection(0);
}
@ -1227,9 +1253,10 @@ describe('ViewContainerRef', () => {
type: Parent,
selectors: [['parent']],
factory: () => new Parent(),
consts: 7,
template: (rf: RenderFlags, cmp: Parent) => {
if (rf & RenderFlags.Create) {
template(0, embeddedTemplate, null, undefined, ['foo', ''], templateRefExtractor);
template(0, embeddedTemplate, 2, null, undefined, ['foo', ''], templateRefExtractor);
elementStart(2, 'child-with-view');
text(3, 'Before projected');
elementStart(4, 'header', ['vcref', '']);
@ -1272,6 +1299,7 @@ describe('ViewContainerRef', () => {
type: ChildWithSelector,
selectors: [['child-with-selector']],
factory: () => new ChildWithSelector(),
consts: 4,
template: (rf: RenderFlags, cmp: ChildWithSelector) => {
if (rf & RenderFlags.Create) {
projectionDef([[['header']]], ['header']);
@ -1303,10 +1331,11 @@ describe('ViewContainerRef', () => {
type: Parent,
selectors: [['parent']],
factory: () => new Parent(),
consts: 5,
template: (rf: RenderFlags, cmp: Parent) => {
let tplRef: any;
if (rf & RenderFlags.Create) {
template(0, embeddedTemplate, null, null, ['foo', ''], templateRefExtractor);
template(0, embeddedTemplate, 2, null, null, ['foo', ''], templateRefExtractor);
elementStart(2, 'child-with-selector');
elementStart(3, 'header', ['vcref', '']);
text(4, 'blah');
@ -1352,10 +1381,11 @@ describe('ViewContainerRef', () => {
type: Parent,
selectors: [['parent']],
factory: () => new Parent(),
consts: 5,
template: (rf: RenderFlags, cmp: Parent) => {
let tplRef: any;
if (rf & RenderFlags.Create) {
template(0, embeddedTemplate, null, null, ['foo', ''], templateRefExtractor);
template(0, embeddedTemplate, 2, null, null, ['foo', ''], templateRefExtractor);
elementStart(2, 'child-with-selector');
elementStart(3, 'footer', ['vcref', '']);
text(4, 'blah');
@ -1415,6 +1445,7 @@ describe('ViewContainerRef', () => {
type: ComponentWithHooks,
selectors: [['hooks']],
factory: () => new ComponentWithHooks(),
consts: 1,
template: (rf: RenderFlags, cmp: ComponentWithHooks) => {
if (rf & RenderFlags.Create) {
text(0);
@ -1429,6 +1460,15 @@ describe('ViewContainerRef', () => {
}
it('should call all hooks in correct order when creating with createEmbeddedView', () => {
function SomeComponent_Template_0(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'hooks');
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'name', bind('C'));
}
}
@Component({
template: `
<ng-template #foo>
@ -1443,16 +1483,10 @@ describe('ViewContainerRef', () => {
type: SomeComponent,
selectors: [['some-comp']],
factory: () => new SomeComponent(),
consts: 4,
template: (rf: RenderFlags, cmp: SomeComponent) => {
if (rf & RenderFlags.Create) {
template(0, (rf: RenderFlags, ctx: any) => {
if (rf & RenderFlags.Create) {
element(0, 'hooks');
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'name', bind('C'));
}
}, null, [], ['foo', ''], templateRefExtractor);
template(0, SomeComponent_Template_0, 1, null, [], ['foo', ''], templateRefExtractor);
element(2, 'hooks', ['vcref', '']);
element(3, 'hooks');
}
@ -1542,6 +1576,7 @@ describe('ViewContainerRef', () => {
type: SomeComponent,
selectors: [['some-comp']],
factory: () => new SomeComponent(),
consts: 2,
template: (rf: RenderFlags, cmp: SomeComponent) => {
if (rf & RenderFlags.Create) {
element(0, 'hooks', ['vcref', '']);