fix(ivy): support separate creation mode and update mode execution in runtime (#23292)

PR Close #23292
This commit is contained in:
Kara Erickson 2018-04-10 20:57:09 -07:00 committed by Victor Berchet
parent 764760ba63
commit de3ca56769
40 changed files with 3121 additions and 2353 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ɵC as C, ɵE as E, ɵT as T, ɵV as V, ɵb as b, ɵcR as cR, ɵcr as cr, ɵdefineComponent as defineComponent, ɵdetectChanges as detectChanges, ɵe as e, ɵsn as sn, ɵt as t, ɵv as v} from '@angular/core'; import {ɵC as C, ɵE as E, ɵRenderFlags as RenderFlags, ɵT as T, ɵV as V, ɵb as b, ɵcR as cR, ɵcr as cr, ɵdefineComponent as defineComponent, ɵdetectChanges as detectChanges, ɵe as e, ɵsn as sn, ɵt as t, ɵv as v} from '@angular/core';
import {ComponentDef} from '@angular/core/src/render3/interfaces/definition'; import {ComponentDef} from '@angular/core/src/render3/interfaces/definition';
import {TableCell, buildTable, emptyTable} from '../util'; import {TableCell, buildTable, emptyTable} from '../util';
@ -18,8 +18,8 @@ export class LargeTableComponent {
static ngComponentDef: ComponentDef<LargeTableComponent> = defineComponent({ static ngComponentDef: ComponentDef<LargeTableComponent> = defineComponent({
type: LargeTableComponent, type: LargeTableComponent,
selectors: [['largetable']], selectors: [['largetable']],
template: function(ctx: LargeTableComponent, cm: boolean) { template: function(rf: RenderFlags, ctx: LargeTableComponent) {
if (cm) { if (rf & RenderFlags.Create) {
E(0, 'table'); E(0, 'table');
{ {
E(1, 'tbody'); E(1, 'tbody');
@ -28,38 +28,44 @@ export class LargeTableComponent {
} }
e(); e();
} }
cR(2); if (rf & RenderFlags.Update) {
{ cR(2);
for (let row of ctx.data) { {
let cm1 = V(1); for (let row of ctx.data) {
{ let rf1 = V(1);
if (cm1) {
E(0, 'tr');
C(1);
e();
}
cR(1);
{ {
for (let cell of row) { if (rf1 & RenderFlags.Create) {
let cm2 = V(2); E(0, 'tr');
C(1);
e();
}
if (rf1 & RenderFlags.Update) {
cR(1);
{ {
if (cm2) { for (let cell of row) {
E(0, 'td'); let rf2 = V(2);
{ T(1); } {
e(); if (rf2 & RenderFlags.Create) {
E(0, 'td');
{ T(1); }
e();
}
if (rf2 & RenderFlags.Update) {
sn(0, 'background-color', b(cell.row % 2 ? '' : 'grey'));
t(1, b(cell.value));
}
}
v();
} }
sn(0, 'background-color', b(cell.row % 2 ? '' : 'grey'));
t(1, b(cell.value));
} }
v(); cr();
} }
} }
cr(); v();
} }
v();
} }
cr();
} }
cr();
}, },
factory: () => new LargeTableComponent(), factory: () => new LargeTableComponent(),
inputs: {data: 'data'} inputs: {data: 'data'}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ɵC as C, ɵE as E, ɵT as T, ɵV as V, ɵb as b, ɵcR as cR, ɵcr as cr, ɵdefineComponent as defineComponent, ɵdetectChanges as _detectChanges, ɵe as e, ɵi1 as i1, ɵp as p, ɵsn as sn, ɵt as t, ɵv as v} from '@angular/core'; import {ɵC as C, ɵE as E, ɵRenderFlags as RenderFlags, ɵT as T, ɵV as V, ɵb as b, ɵcR as cR, ɵcr as cr, ɵdefineComponent as defineComponent, ɵdetectChanges as _detectChanges, ɵe as e, ɵi1 as i1, ɵp as p, ɵsn as sn, ɵt as t, ɵv as v} from '@angular/core';
import {ComponentDef} from '@angular/core/src/render3/interfaces/definition'; import {ComponentDef} from '@angular/core/src/render3/interfaces/definition';
import {TreeNode, buildTree, emptyTree} from '../util'; import {TreeNode, buildTree, emptyTree} from '../util';
@ -38,46 +38,52 @@ export class TreeComponent {
static ngComponentDef: ComponentDef<TreeComponent> = defineComponent({ static ngComponentDef: ComponentDef<TreeComponent> = defineComponent({
type: TreeComponent, type: TreeComponent,
selectors: [['tree']], selectors: [['tree']],
template: function(ctx: TreeComponent, cm: boolean) { template: function(rf: RenderFlags, ctx: TreeComponent) {
if (cm) { if (rf & RenderFlags.Create) {
E(0, 'span'); E(0, 'span');
{ T(1); } { T(1); }
e(); e();
C(2); C(2);
C(3); C(3);
} }
sn(0, 'background-color', b(ctx.data.depth % 2 ? '' : 'grey')); if (rf & RenderFlags.Update) {
t(1, i1(' ', ctx.data.value, ' ')); sn(0, 'background-color', b(ctx.data.depth % 2 ? '' : 'grey'));
cR(2); t(1, i1(' ', ctx.data.value, ' '));
{ cR(2);
if (ctx.data.left != null) { {
let cm0 = V(0); if (ctx.data.left != null) {
{ let rf0 = V(0);
if (cm0) { {
E(0, 'tree'); if (rf0 & RenderFlags.Create) {
e(); E(0, 'tree');
e();
}
if (rf0 & RenderFlags.Update) {
p(0, 'data', b(ctx.data.left));
}
} }
p(0, 'data', b(ctx.data.left)); v();
} }
v();
} }
} cr();
cr(); cR(3);
cR(3); {
{ if (ctx.data.right != null) {
if (ctx.data.right != null) { let rf0 = V(0);
let cm0 = V(0); {
{ if (rf0 & RenderFlags.Create) {
if (cm0) { E(0, 'tree');
E(0, 'tree'); e();
e(); }
if (rf0 & RenderFlags.Update) {
p(0, 'data', b(ctx.data.right));
}
} }
p(0, 'data', b(ctx.data.right)); v();
} }
v();
} }
cr();
} }
cr();
}, },
factory: () => new TreeComponent, factory: () => new TreeComponent,
inputs: {data: 'data'}, inputs: {data: 'data'},
@ -92,17 +98,17 @@ export class TreeFunction {
static ngComponentDef: ComponentDef<TreeFunction> = defineComponent({ static ngComponentDef: ComponentDef<TreeFunction> = defineComponent({
type: TreeFunction, type: TreeFunction,
selectors: [['tree']], selectors: [['tree']],
template: function(ctx: TreeFunction, cm: boolean) { template: function(rf: RenderFlags, ctx: TreeFunction) {
// bit of a hack // bit of a hack
TreeTpl(ctx.data, cm); TreeTpl(rf, ctx.data);
}, },
factory: () => new TreeFunction, factory: () => new TreeFunction,
inputs: {data: 'data'} inputs: {data: 'data'}
}); });
} }
export function TreeTpl(ctx: TreeNode, cm: boolean) { export function TreeTpl(rf: RenderFlags, ctx: TreeNode) {
if (cm) { if (rf & RenderFlags.Create) {
E(0, 'tree'); E(0, 'tree');
{ {
E(1, 'span'); E(1, 'span');
@ -113,24 +119,26 @@ export function TreeTpl(ctx: TreeNode, cm: boolean) {
} }
e(); e();
} }
sn(1, 'background-color', b(ctx.depth % 2 ? '' : 'grey')); if (rf & RenderFlags.Update) {
t(2, i1(' ', ctx.value, ' ')); sn(1, 'background-color', b(ctx.depth % 2 ? '' : 'grey'));
cR(3); t(2, i1(' ', ctx.value, ' '));
{ cR(3);
if (ctx.left != null) { {
let cm0 = V(0); if (ctx.left != null) {
{ TreeTpl(ctx.left, cm0); } let rf0 = V(0);
v(); { TreeTpl(rf0, ctx.left); }
v();
}
} }
} cr();
cr(); cR(4);
cR(4); {
{ if (ctx.right != null) {
if (ctx.right != null) { let rf0 = V(0);
let cm0 = V(0); { TreeTpl(rf0, ctx.right); }
{ TreeTpl(ctx.right, cm0); } v();
v(); }
} }
cr();
} }
cr();
} }

View File

@ -15,6 +15,7 @@ export {
renderComponent as ɵrenderComponent, renderComponent as ɵrenderComponent,
ComponentType as ɵComponentType, ComponentType as ɵComponentType,
DirectiveType as ɵDirectiveType, DirectiveType as ɵDirectiveType,
RenderFlags as ɵRenderFlags,
directiveInject as ɵdirectiveInject, directiveInject as ɵdirectiveInject,
injectTemplateRef as ɵinjectTemplateRef, injectTemplateRef as ɵinjectTemplateRef,
injectViewContainerRef as ɵinjectViewContainerRef, injectViewContainerRef as ɵinjectViewContainerRef,

View File

@ -12,6 +12,7 @@ import {InjectFlags} from './di';
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveType, PipeDef} from './interfaces/definition'; import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveType, PipeDef} from './interfaces/definition';
export {InjectFlags, QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, injectAttribute, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di'; export {InjectFlags, QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, injectAttribute, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di';
export {RenderFlags} from './interfaces/definition';
export {CssSelectorList} from './interfaces/projection'; export {CssSelectorList} from './interfaces/projection';

View File

@ -17,9 +17,9 @@ import {CurrentMatchesList, LView, LViewFlags, LifecycleStage, RootContext, TDat
import {LContainerNode, LElementNode, LNode, LNodeType, TNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue,} from './interfaces/node'; import {LContainerNode, LElementNode, LNode, LNodeType, TNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue,} from './interfaces/node';
import {assertNodeType} from './node_assert'; import {assertNodeType} from './node_assert';
import {appendChild, insertChild, insertView, appendProjectedNode, removeView, canInsertNativeNode} from './node_manipulation'; import {appendChild, insertChild, insertView, appendProjectedNode, removeView, canInsertNativeNode, createTextNode} from './node_manipulation';
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher'; import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, DirectiveType, PipeDef, PipeDefListOrFactory} from './interfaces/definition'; import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, DirectiveType, PipeDef, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer'; import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
import {isDifferent, stringify} from './util'; import {isDifferent, stringify} from './util';
import {executeHooks, queueLifecycleHooks, queueInitHooks, executeInitHooks} from './hooks'; import {executeHooks, queueLifecycleHooks, queueInitHooks, executeInitHooks} from './hooks';
@ -458,7 +458,7 @@ export function renderEmbeddedTemplate<T>(
try { try {
isParent = true; isParent = true;
previousOrParentNode = null !; previousOrParentNode = null !;
let cm: boolean = false; let rf: RenderFlags = RenderFlags.Update;
if (viewNode == null) { if (viewNode == null) {
// TODO: revisit setting currentView when re-writing view containers // TODO: revisit setting currentView when re-writing view containers
const directives = currentView && currentView.tView.directiveRegistry; const directives = currentView && currentView.tView.directiveRegistry;
@ -468,11 +468,11 @@ export function renderEmbeddedTemplate<T>(
const lView = createLView(-1, renderer, tView, template, context, LViewFlags.CheckAlways); const lView = createLView(-1, renderer, tView, template, context, LViewFlags.CheckAlways);
viewNode = createLNode(null, LNodeType.View, null, lView); viewNode = createLNode(null, LNodeType.View, null, lView);
cm = true; rf = RenderFlags.Create;
} }
oldView = enterView(viewNode.data, viewNode); oldView = enterView(viewNode.data, viewNode);
template(context, cm); template(rf, context);
refreshDirectives(); refreshDirectives();
refreshDynamicChildren(); refreshDynamicChildren();
@ -492,7 +492,8 @@ export function renderComponentOrTemplate<T>(
rendererFactory.begin(); rendererFactory.begin();
} }
if (template) { if (template) {
template(componentOrContext !, creationMode); template(getRenderFlags(hostView), componentOrContext !);
refreshDynamicChildren();
refreshDirectives(); refreshDirectives();
} else { } else {
executeInitAndContentHooks(); executeInitAndContentHooks();
@ -510,6 +511,20 @@ export function renderComponentOrTemplate<T>(
} }
} }
/**
* This function returns the default configuration of rendering flags depending on when the
* template is in creation mode or update mode. By default, the update block is run with the
* creation block when the view is in creation mode. Otherwise, the update block is run
* alone.
*
* Dynamically created views do NOT use this configuration (update block and create block are
* always run separately).
*/
function getRenderFlags(view: LView): RenderFlags {
return view.flags & LViewFlags.CreationMode ? RenderFlags.Create | RenderFlags.Update :
RenderFlags.Update;
}
////////////////////////// //////////////////////////
//// Element //// Element
////////////////////////// //////////////////////////
@ -1146,10 +1161,7 @@ export function elementStyle<T>(
export function text(index: number, value?: any): void { export function text(index: number, value?: any): void {
ngDevMode && ngDevMode &&
assertNull(currentView.bindingStartIndex, 'text nodes should be created before bindings'); assertNull(currentView.bindingStartIndex, 'text nodes should be created before bindings');
const textNode = value != null ? const textNode = value != null ? createTextNode(value, renderer) : null;
(isProceduralRenderer(renderer) ? renderer.createText(stringify(value)) :
renderer.createTextNode(stringify(value))) :
null;
const node = createLNode(index, LNodeType.Element, textNode); const node = createLNode(index, LNodeType.Element, textNode);
// Text nodes are self closing. // Text nodes are self closing.
isParent = false; isParent = false;
@ -1174,14 +1186,11 @@ export function textBinding<T>(index: number, value: T | NO_CHANGE): void {
existingNode.native.textContent = stringify(value)); existingNode.native.textContent = stringify(value));
} else { } else {
// Node was created but DOM node creation was delayed. Create and append now. // Node was created but DOM node creation was delayed. Create and append now.
existingNode.native = isProceduralRenderer(renderer) ? existingNode.native = createTextNode(value, renderer);
renderer.createText(stringify(value)) :
renderer.createTextNode(stringify(value));
insertChild(existingNode, currentView); insertChild(existingNode, currentView);
} }
} }
////////////////////////// //////////////////////////
//// Directive //// Directive
////////////////////////// //////////////////////////
@ -1491,18 +1500,18 @@ function scanForView(
* @param viewBlockId The ID of this view * @param viewBlockId The ID of this view
* @return boolean Whether or not this view is in creation mode * @return boolean Whether or not this view is in creation mode
*/ */
export function embeddedViewStart(viewBlockId: number): boolean { export function embeddedViewStart(viewBlockId: number): RenderFlags {
const container = const container =
(isParent ? previousOrParentNode : previousOrParentNode.parent !) as LContainerNode; (isParent ? previousOrParentNode : previousOrParentNode.parent !) as LContainerNode;
ngDevMode && assertNodeType(container, LNodeType.Container); ngDevMode && assertNodeType(container, LNodeType.Container);
const lContainer = container.data; const lContainer = container.data;
const existingViewNode = scanForView(container, lContainer.nextIndex, viewBlockId); let viewNode: LViewNode|null = scanForView(container, lContainer.nextIndex, viewBlockId);
if (existingViewNode) { if (viewNode) {
previousOrParentNode = existingViewNode; previousOrParentNode = viewNode;
ngDevMode && assertNodeType(previousOrParentNode, LNodeType.View); ngDevMode && assertNodeType(previousOrParentNode, LNodeType.View);
isParent = true; isParent = true;
enterView((existingViewNode as LViewNode).data, existingViewNode as LViewNode); enterView(viewNode.data, viewNode);
} else { } else {
// When we create a new LView, we always reset the state of the instructions. // When we create a new LView, we always reset the state of the instructions.
const newView = createLView( const newView = createLView(
@ -1512,9 +1521,9 @@ export function embeddedViewStart(viewBlockId: number): boolean {
newView.queries = lContainer.queries.enterView(lContainer.nextIndex); newView.queries = lContainer.queries.enterView(lContainer.nextIndex);
} }
enterView(newView, createLNode(null, LNodeType.View, null, newView)); enterView(newView, viewNode = createLNode(null, LNodeType.View, null, newView));
} }
return !existingViewNode; return getRenderFlags(viewNode.data);
} }
/** /**
@ -1919,7 +1928,7 @@ export function detectChangesInternal<T>(
const template = def.template; const template = def.template;
try { try {
template(component, creationMode); template(getRenderFlags(hostView), component);
refreshDirectives(); refreshDirectives();
refreshDynamicChildren(); refreshDynamicChildren();
} finally { } finally {
@ -1967,13 +1976,7 @@ export const NO_CHANGE = {} as NO_CHANGE;
* (ie `bind()`, `interpolationX()`, `pureFunctionX()`) * (ie `bind()`, `interpolationX()`, `pureFunctionX()`)
*/ */
function initBindings() { function initBindings() {
// `bindingIndex` is initialized when the view is first entered when not in creation mode bindingIndex = currentView.bindingStartIndex = data.length;
ngDevMode &&
assertEqual(
creationMode, true, 'should only be called in creationMode for performance reasons');
if (currentView.bindingStartIndex == null) {
bindingIndex = currentView.bindingStartIndex = data.length;
}
} }
/** /**
@ -1982,7 +1985,7 @@ function initBindings() {
* @param value Value to diff * @param value Value to diff
*/ */
export function bind<T>(value: T | NO_CHANGE): T|NO_CHANGE { export function bind<T>(value: T | NO_CHANGE): T|NO_CHANGE {
if (creationMode) { if (currentView.bindingStartIndex == null) {
initBindings(); initBindings();
return data[bindingIndex++] = value; return data[bindingIndex++] = value;
} }
@ -2166,7 +2169,7 @@ export function consumeBinding(): any {
export function bindingUpdated(value: any): boolean { export function bindingUpdated(value: any): boolean {
ngDevMode && assertNotEqual(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.'); ngDevMode && assertNotEqual(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
if (creationMode) { if (currentView.bindingStartIndex == null) {
initBindings(); initBindings();
} else if (isDifferent(data[bindingIndex], value)) { } else if (isDifferent(data[bindingIndex], value)) {
throwErrorIfNoChangesMode(creationMode, checkNoChangesMode, data[bindingIndex], value); throwErrorIfNoChangesMode(creationMode, checkNoChangesMode, data[bindingIndex], value);

View File

@ -6,22 +6,34 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ChangeDetectionStrategy} from '../../change_detection/constants';
import {PipeTransform} from '../../change_detection/pipe_transform';
import {Provider} from '../../core'; import {Provider} from '../../core';
import {RendererType2} from '../../render/api'; import {RendererType2} from '../../render/api';
import {Type} from '../../type'; import {Type} from '../../type';
import {resolveRendererType2} from '../../view/util';
import {CssSelectorList} from './projection'; import {CssSelectorList} from './projection';
/** /**
* Definition of what a template rendering function should look like. * Definition of what a template rendering function should look like.
*/ */
export type ComponentTemplate<T> = { export type ComponentTemplate<T> = {
(ctx: T, creationMode: boolean): void; ngPrivateData?: never; (rf: RenderFlags, ctx: T): void; ngPrivateData?: never;
}; };
/**
* Flags passed into template functions to determine which blocks (i.e. creation, update)
* should be executed.
*
* Typically, a template runs both the creation block and the update block on initialization and
* subsequent runs only execute the update block. However, dynamically created views require that
* the creation block be executed separately from the update block (for backwards compat).
*/
export const enum RenderFlags {
/* Whether to run the creation block (e.g. create elements and directives) */
Create = 0b01,
/* Whether to run the update block (e.g. refresh bindings) */
Update = 0b10
}
/** /**
* A subclass of `Type` which has a static `ngComponentDef`:`ComponentDef` field making it * A subclass of `Type` which has a static `ngComponentDef`:`ComponentDef` field making it
* consumable for rendering. * consumable for rendering.

View File

@ -11,9 +11,10 @@ import {callHooks} from './hooks';
import {LContainer, unusedValueExportToPlacateAjd as unused1} from './interfaces/container'; import {LContainer, unusedValueExportToPlacateAjd as unused1} from './interfaces/container';
import {LContainerNode, LElementNode, LNode, LNodeType, LProjectionNode, LTextNode, LViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node'; import {LContainerNode, LElementNode, LNode, LNodeType, LProjectionNode, LTextNode, LViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node';
import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection'; import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection';
import {ProceduralRenderer3, RElement, RNode, RText, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer'; import {ProceduralRenderer3, RElement, RNode, RText, Renderer3, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer';
import {HookData, LView, LViewOrLContainer, TView, unusedValueExportToPlacateAjd as unused5} from './interfaces/view'; import {HookData, LView, LViewOrLContainer, TView, unusedValueExportToPlacateAjd as unused5} from './interfaces/view';
import {assertNodeType} from './node_assert'; import {assertNodeType} from './node_assert';
import {stringify} from './util';
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5; const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5;
@ -143,6 +144,11 @@ function findFirstRNode(rootNode: LNode): RElement|RText|null {
return null; return null;
} }
export function createTextNode(value: any, renderer: Renderer3): RText {
return isProceduralRenderer(renderer) ? renderer.createText(stringify(value)) :
renderer.createTextNode(stringify(value));
}
/** /**
* Adds or removes all DOM elements associated with a view. * Adds or removes all DOM elements associated with a view.
* *
@ -174,6 +180,12 @@ export function addRemoveViewFromContainer(
const renderer = container.view.renderer; const renderer = container.view.renderer;
if (node.type === LNodeType.Element) { if (node.type === LNodeType.Element) {
if (insertMode) { if (insertMode) {
if (!node.native) {
// If the native element doesn't exist, this is a bound text node that hasn't yet been
// created because update mode has not run (occurs when a bound text node is a root
// node of a dynamically created view). See textBinding() in instructions for ctx.
(node as LTextNode).native = createTextNode('', renderer);
}
isProceduralRenderer(renderer) ? isProceduralRenderer(renderer) ?
renderer.insertBefore(parent, node.native !, beforeNode as RNode | null) : renderer.insertBefore(parent, node.native !, beforeNode as RNode | null) :
parent.insertBefore(node.native !, beforeNode as RNode | null, true); parent.insertBefore(node.native !, beforeNode as RNode | null, true);

View File

@ -62,6 +62,9 @@
{ {
"name": "createTView" "name": "createTView"
}, },
{
"name": "createTextNode"
},
{ {
"name": "currentView" "name": "currentView"
}, },
@ -104,6 +107,9 @@
{ {
"name": "getOrCreateTView" "name": "getOrCreateTView"
}, },
{
"name": "getRenderFlags"
},
{ {
"name": "hostElement" "name": "hostElement"
}, },

View File

@ -269,6 +269,9 @@
{ {
"name": "createTView" "name": "createTView"
}, },
{
"name": "createTextNode"
},
{ {
"name": "currentView" "name": "currentView"
}, },
@ -398,6 +401,9 @@
{ {
"name": "getPreviousOrParentNode" "name": "getPreviousOrParentNode"
}, },
{
"name": "getRenderFlags"
},
{ {
"name": "getRenderer" "name": "getRenderer"
}, },

View File

@ -8,7 +8,7 @@
import {defineComponent} from '../../src/render3/index'; import {defineComponent} from '../../src/render3/index';
import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, text} from '../../src/render3/instructions'; import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, text} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {document, renderComponent} from './render_util'; import {document, renderComponent} from './render_util';
describe('iv perf test', () => { describe('iv perf test', () => {
@ -35,25 +35,27 @@ describe('iv perf test', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: Component, type: Component,
selectors: [['div']], selectors: [['div']],
template: function Template(ctx: any, cm: any) { template: function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
for (let i = 0; i < count; i++) { {
let cm0 = embeddedViewStart(0); for (let i = 0; i < count; i++) {
{ let rf0 = embeddedViewStart(0);
if (cm0) { {
elementStart(0, 'div'); if (rf0 & RenderFlags.Create) {
text(1, '-'); elementStart(0, 'div');
elementEnd(); text(1, '-');
elementEnd();
}
} }
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}, },
factory: () => new Component factory: () => new Component
}); });

View File

@ -12,7 +12,7 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, DoCheck} from '../../src/cor
import {getRenderedText, whenRendered} from '../../src/render3/component'; import {getRenderedText, whenRendered} from '../../src/render3/component';
import {LifecycleHooksFeature, defineComponent, defineDirective, injectChangeDetectorRef} from '../../src/render3/index'; import {LifecycleHooksFeature, defineComponent, defineDirective, injectChangeDetectorRef} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, detectChanges, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, listener, markDirty, text, textBinding, tick} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, detectChanges, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, listener, markDirty, text, textBinding, tick} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {containerEl, createComponent, renderComponent, requestAnimationFrame} from './render_util'; import {containerEl, createComponent, renderComponent, requestAnimationFrame} from './render_util';
describe('change detection', () => { describe('change detection', () => {
@ -27,13 +27,15 @@ describe('change detection', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-comp']], selectors: [['my-comp']],
factory: () => new MyComponent(), factory: () => new MyComponent(),
template: (ctx: MyComponent, cm: boolean) => { template: (rf: RenderFlags, ctx: MyComponent) => {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
text(1); text(1);
elementEnd(); elementEnd();
} }
textBinding(1, bind(ctx.value)); if (rf & RenderFlags.Update) {
textBinding(1, bind(ctx.value));
}
} }
}); });
} }
@ -102,8 +104,8 @@ describe('change detection', () => {
* {{ doCheckCount }} - {{ name }} * {{ doCheckCount }} - {{ name }}
* <button (click)="onClick()"></button> * <button (click)="onClick()"></button>
*/ */
template: (ctx: MyComponent, cm: boolean) => { template: (rf: RenderFlags, ctx: MyComponent) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
elementStart(1, 'button'); elementStart(1, 'button');
{ {
@ -126,12 +128,14 @@ describe('change detection', () => {
selectors: [['my-app']], selectors: [['my-app']],
factory: () => new MyApp(), factory: () => new MyApp(),
/** <my-comp [name]="name"></my-comp> */ /** <my-comp [name]="name"></my-comp> */
template: (ctx: MyApp, cm: boolean) => { template: (rf: RenderFlags, ctx: MyApp) => {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp'); elementStart(0, 'my-comp');
elementEnd(); elementEnd();
} }
elementProperty(0, 'name', bind(ctx.name)); if (rf & RenderFlags.Update) {
elementProperty(0, 'name', bind(ctx.name));
}
}, },
directives: () => [MyComponent] directives: () => [MyComponent]
}); });
@ -195,8 +199,8 @@ describe('change detection', () => {
it('should not check OnPush components in update mode when parent events occur', () => { it('should not check OnPush components in update mode when parent events occur', () => {
function noop() {} function noop() {}
const ButtonParent = createComponent('button-parent', function(ctx: any, cm: boolean) { const ButtonParent = createComponent('button-parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp'); elementStart(0, 'my-comp');
elementEnd(); elementEnd();
elementStart(1, 'button', ['id', 'parent']); elementStart(1, 'button', ['id', 'parent']);
@ -226,21 +230,23 @@ describe('change detection', () => {
selectors: [['button-parent']], selectors: [['button-parent']],
factory: () => parent = new ButtonParent(), factory: () => parent = new ButtonParent(),
/** {{ doCheckCount }} - <my-comp></my-comp> */ /** {{ doCheckCount }} - <my-comp></my-comp> */
template: (ctx: ButtonParent, cm: boolean) => { template: (rf: RenderFlags, ctx: ButtonParent) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
elementStart(1, 'my-comp'); elementStart(1, 'my-comp');
elementEnd(); elementEnd();
} }
textBinding(0, interpolation1('', ctx.doCheckCount, ' - ')); if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', ctx.doCheckCount, ' - '));
}
}, },
directives: () => [MyComponent], directives: () => [MyComponent],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}); });
} }
const MyButtonApp = createComponent('my-button-app', function(ctx: any, cm: boolean) { const MyButtonApp = createComponent('my-button-app', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button-parent'); elementStart(0, 'button-parent');
elementEnd(); elementEnd();
} }
@ -285,11 +291,13 @@ describe('change detection', () => {
selectors: [['my-comp']], selectors: [['my-comp']],
factory: () => myComp = new MyComp(injectChangeDetectorRef()), factory: () => myComp = new MyComp(injectChangeDetectorRef()),
/** {{ name }} */ /** {{ name }} */
template: (ctx: MyComp, cm: boolean) => { template: (rf: RenderFlags, ctx: MyComp) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, bind(ctx.name)); if (rf & RenderFlags.Update) {
textBinding(0, bind(ctx.name));
}
}, },
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}); });
@ -310,13 +318,15 @@ describe('change detection', () => {
* {{ doCheckCount}} - * {{ doCheckCount}} -
* <my-comp></my-comp> * <my-comp></my-comp>
*/ */
template: (ctx: ParentComp, cm: boolean) => { template: (rf: RenderFlags, ctx: ParentComp) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
elementStart(1, 'my-comp'); elementStart(1, 'my-comp');
elementEnd(); elementEnd();
} }
textBinding(0, interpolation1('', ctx.doCheckCount, ' - ')); if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', ctx.doCheckCount, ' - '));
}
}, },
directives: () => [MyComp] directives: () => [MyComp]
}); });
@ -388,8 +398,8 @@ describe('change detection', () => {
it('should check component view when called by directive on component node', () => { it('should check component view when called by directive on component node', () => {
/** <my-comp dir></my-comp> */ /** <my-comp dir></my-comp> */
const MyApp = createComponent('my-app', function(ctx: any, cm: boolean) { const MyApp = createComponent('my-app', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp', ['dir', '']); elementStart(0, 'my-comp', ['dir', '']);
elementEnd(); elementEnd();
} }
@ -408,13 +418,15 @@ describe('change detection', () => {
* {{ name }} * {{ name }}
* <div dir></div> * <div dir></div>
*/ */
const MyApp = createComponent('my-app', function(ctx: any, cm: boolean) { const MyApp = createComponent('my-app', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
elementStart(1, 'div', ['dir', '']); elementStart(1, 'div', ['dir', '']);
elementEnd(); elementEnd();
} }
textBinding(1, bind(ctx.value)); if (rf & RenderFlags.Update) {
textBinding(1, bind(ctx.value));
}
}, [Dir]); }, [Dir]);
const app = renderComponent(MyApp); const app = renderComponent(MyApp);
@ -444,23 +456,26 @@ describe('change detection', () => {
* <div dir></div> * <div dir></div>
* % } * % }
*/ */
template: function(ctx: MyApp, cm: boolean) { template: function(rf: RenderFlags, ctx: MyApp) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
container(1); container(1);
} }
textBinding(0, bind(ctx.name)); if (rf & RenderFlags.Update) {
containerRefreshStart(1); textBinding(0, bind(ctx.name));
{ containerRefreshStart(1);
if (ctx.showing) { {
if (embeddedViewStart(0)) { if (ctx.showing) {
elementStart(0, 'div', ['dir', '']); let rf0 = embeddedViewStart(0);
elementEnd(); if (rf0 & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '']);
elementEnd();
}
} }
embeddedViewEnd();
} }
embeddedViewEnd(); containerRefreshEnd();
} }
containerRefreshEnd();
}, },
directives: [Dir] directives: [Dir]
}); });
@ -490,11 +505,13 @@ describe('change detection', () => {
selectors: [['detect-changes-comp']], selectors: [['detect-changes-comp']],
factory: () => new DetectChangesComp(injectChangeDetectorRef()), factory: () => new DetectChangesComp(injectChangeDetectorRef()),
/** {{ value }} */ /** {{ value }} */
template: (ctx: DetectChangesComp, cm: boolean) => { template: (rf: RenderFlags, ctx: DetectChangesComp) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, bind(ctx.value)); if (rf & RenderFlags.Update) {
textBinding(0, bind(ctx.value));
}
} }
}); });
} }
@ -519,11 +536,13 @@ describe('change detection', () => {
selectors: [['detect-changes-comp']], selectors: [['detect-changes-comp']],
factory: () => new DetectChangesComp(injectChangeDetectorRef()), factory: () => new DetectChangesComp(injectChangeDetectorRef()),
/** {{ doCheckCount }} */ /** {{ doCheckCount }} */
template: (ctx: DetectChangesComp, cm: boolean) => { template: (rf: RenderFlags, ctx: DetectChangesComp) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, bind(ctx.doCheckCount)); if (rf & RenderFlags.Update) {
textBinding(0, bind(ctx.doCheckCount));
}
} }
}); });
} }
@ -545,8 +564,8 @@ describe('change detection', () => {
selectors: [['my-app']], selectors: [['my-app']],
factory: () => new MyApp(injectChangeDetectorRef()), factory: () => new MyApp(injectChangeDetectorRef()),
/** <detached-comp></detached-comp> */ /** <detached-comp></detached-comp> */
template: (ctx: MyApp, cm: boolean) => { template: (rf: RenderFlags, ctx: MyApp) => {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'detached-comp'); elementStart(0, 'detached-comp');
elementEnd(); elementEnd();
} }
@ -568,11 +587,13 @@ describe('change detection', () => {
selectors: [['detached-comp']], selectors: [['detached-comp']],
factory: () => comp = new DetachedComp(injectChangeDetectorRef()), factory: () => comp = new DetachedComp(injectChangeDetectorRef()),
/** {{ value }} */ /** {{ value }} */
template: (ctx: DetachedComp, cm: boolean) => { template: (rf: RenderFlags, ctx: DetachedComp) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, bind(ctx.value)); if (rf & RenderFlags.Update) {
textBinding(0, bind(ctx.value));
}
} }
}); });
} }
@ -664,11 +685,13 @@ describe('change detection', () => {
selectors: [['on-push-comp']], selectors: [['on-push-comp']],
factory: () => onPushComp = new OnPushComp(injectChangeDetectorRef()), factory: () => onPushComp = new OnPushComp(injectChangeDetectorRef()),
/** {{ value }} */ /** {{ value }} */
template: (ctx: OnPushComp, cm: boolean) => { template: (rf: RenderFlags, ctx: any) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, bind(ctx.value)); if (rf & RenderFlags.Update) {
textBinding(0, bind(ctx.value));
}
}, },
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
inputs: {value: 'value'} inputs: {value: 'value'}
@ -676,12 +699,14 @@ describe('change detection', () => {
} }
/** <on-push-comp [value]="value"></on-push-comp> */ /** <on-push-comp [value]="value"></on-push-comp> */
const OnPushApp = createComponent('on-push-app', function(ctx: any, cm: boolean) { const OnPushApp = createComponent('on-push-app', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'on-push-comp'); elementStart(0, 'on-push-comp');
elementEnd(); elementEnd();
} }
elementProperty(0, 'value', bind(ctx.value)); if (rf & RenderFlags.Update) {
elementProperty(0, 'value', bind(ctx.value));
}
}, [OnPushComp]); }, [OnPushComp]);
const app = renderComponent(OnPushApp); const app = renderComponent(OnPushApp);
@ -720,11 +745,13 @@ describe('change detection', () => {
selectors: [['on-push-comp']], selectors: [['on-push-comp']],
factory: () => comp = new OnPushComp(injectChangeDetectorRef()), factory: () => comp = new OnPushComp(injectChangeDetectorRef()),
/** {{ value }} */ /** {{ value }} */
template: (ctx: OnPushComp, cm: boolean) => { template: (rf: RenderFlags, ctx: OnPushComp) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, bind(ctx.value)); if (rf & RenderFlags.Update) {
textBinding(0, bind(ctx.value));
}
}, },
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}); });
@ -741,13 +768,15 @@ describe('change detection', () => {
* {{ value }} - * {{ value }} -
* <on-push-comp></on-push-comp> * <on-push-comp></on-push-comp>
*/ */
template: (ctx: OnPushParent, cm: boolean) => { template: (rf: RenderFlags, ctx: OnPushParent) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
elementStart(1, 'on-push-comp'); elementStart(1, 'on-push-comp');
elementEnd(); elementEnd();
} }
textBinding(0, interpolation1('', ctx.value, ' - ')); if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', ctx.value, ' - '));
}
}, },
directives: () => [OnPushComp], directives: () => [OnPushComp],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
@ -810,23 +839,26 @@ describe('change detection', () => {
* <on-push-comp></on-push-comp> * <on-push-comp></on-push-comp>
* % } * % }
*/ */
template: (ctx: EmbeddedViewParent, cm: boolean) => { template: (rf: RenderFlags, ctx: any) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
container(1); container(1);
} }
textBinding(0, interpolation1('', ctx.value, ' - ')); if (rf & RenderFlags.Update) {
containerRefreshStart(1); textBinding(0, interpolation1('', ctx.value, ' - '));
{ containerRefreshStart(1);
if (ctx.showing) { {
if (embeddedViewStart(0)) { if (ctx.showing) {
elementStart(0, 'on-push-comp'); let rf0 = embeddedViewStart(0);
elementEnd(); if (rf0 & RenderFlags.Create) {
elementStart(0, 'on-push-comp');
elementEnd();
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}, },
directives: () => [OnPushComp], directives: () => [OnPushComp],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
@ -877,11 +909,13 @@ describe('change detection', () => {
type: NoChangesComp, type: NoChangesComp,
selectors: [['no-changes-comp']], selectors: [['no-changes-comp']],
factory: () => comp = new NoChangesComp(injectChangeDetectorRef()), factory: () => comp = new NoChangesComp(injectChangeDetectorRef()),
template: (ctx: NoChangesComp, cm: boolean) => { template: (rf: RenderFlags, ctx: NoChangesComp) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, bind(ctx.value)); if (rf & RenderFlags.Update) {
textBinding(0, bind(ctx.value));
}
} }
}); });
} }
@ -899,13 +933,15 @@ describe('change detection', () => {
* {{ value }} - * {{ value }} -
* <no-changes-comp></no-changes-comp> * <no-changes-comp></no-changes-comp>
*/ */
template: (ctx: AppComp, cm: boolean) => { template: (rf: RenderFlags, ctx: AppComp) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
elementStart(1, 'no-changes-comp'); elementStart(1, 'no-changes-comp');
elementEnd(); elementEnd();
} }
textBinding(0, interpolation1('', ctx.value, ' - ')); if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', ctx.value, ' - '));
}
}, },
directives: () => [NoChangesComp] directives: () => [NoChangesComp]
}); });
@ -960,21 +996,26 @@ describe('change detection', () => {
* {{ value }} * {{ value }}
* %} * %}
*/ */
template: (ctx: EmbeddedViewApp, cm: boolean) => { template: (rf: RenderFlags, ctx: EmbeddedViewApp) => {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (ctx.showing) { {
if (embeddedViewStart(0)) { if (ctx.showing) {
text(0); let rf0 = embeddedViewStart(0);
if (rf0 & RenderFlags.Create) {
text(0);
}
if (rf0 & RenderFlags.Update) {
textBinding(0, bind(ctx.value));
}
embeddedViewEnd();
} }
textBinding(0, bind(ctx.value));
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
}); });
} }

View File

@ -10,7 +10,7 @@ import {NgForOfContext} from '@angular/common';
import {defineComponent} from '../../src/render3/index'; import {defineComponent} from '../../src/render3/index';
import {bind, container, elementEnd, elementProperty, elementStart, interpolation3, text, textBinding, tick} from '../../src/render3/instructions'; import {bind, container, elementEnd, elementProperty, elementStart, interpolation3, text, textBinding, tick} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {NgForOf} from './common_with_def'; import {NgForOf} from './common_with_def';
import {ComponentFixture} from './render_util'; import {ComponentFixture} from './render_util';
@ -28,21 +28,25 @@ describe('@angular/common integration', () => {
// <ul> // <ul>
// <li *ngFor="let item of items">{{item}}</li> // <li *ngFor="let item of items">{{item}}</li>
// </ul> // </ul>
template: (myApp: MyApp, cm: boolean) => { template: (rf: RenderFlags, myApp: MyApp) => {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'ul'); elementStart(0, 'ul');
{ container(1, liTemplate, undefined, ['ngForOf', '']); } { container(1, liTemplate, undefined, ['ngForOf', '']); }
elementEnd(); elementEnd();
} }
elementProperty(1, 'ngForOf', bind(myApp.items)); if (rf & RenderFlags.Update) {
elementProperty(1, 'ngForOf', bind(myApp.items));
}
function liTemplate(row: NgForOfContext<string>, cm: boolean) { function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (cm) { if (rf1 & RenderFlags.Create) {
elementStart(0, 'li'); elementStart(0, 'li');
{ text(1); } { text(1); }
elementEnd(); elementEnd();
} }
textBinding(1, bind(row.$implicit)); if (rf1 & RenderFlags.Update) {
textBinding(1, bind(row.$implicit));
}
} }
}, },
directives: () => [NgForOf] directives: () => [NgForOf]
@ -84,22 +88,26 @@ describe('@angular/common integration', () => {
// <ul> // <ul>
// <li *ngFor="let item of items">{{index}} of {{count}}: {{item}}</li> // <li *ngFor="let item of items">{{index}} of {{count}}: {{item}}</li>
// </ul> // </ul>
template: (myApp: MyApp, cm: boolean) => { template: (rf: RenderFlags, myApp: MyApp) => {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'ul'); elementStart(0, 'ul');
{ container(1, liTemplate, undefined, ['ngForOf', '']); } { container(1, liTemplate, undefined, ['ngForOf', '']); }
elementEnd(); elementEnd();
} }
elementProperty(1, 'ngForOf', bind(myApp.items)); if (rf & RenderFlags.Update) {
elementProperty(1, 'ngForOf', bind(myApp.items));
}
function liTemplate(row: NgForOfContext<string>, cm: boolean) { function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
if (cm) { if (rf1 & RenderFlags.Create) {
elementStart(0, 'li'); elementStart(0, 'li');
{ text(1); } { text(1); }
elementEnd(); elementEnd();
} }
textBinding( if (rf1 & RenderFlags.Update) {
1, interpolation3('', row.index, ' of ', row.count, ': ', row.$implicit, '')); textBinding(
1, interpolation3('', row.index, ' of ', row.count, ': ', row.$implicit, ''));
}
} }
}, },
directives: () => [NgForOf] directives: () => [NgForOf]

View File

@ -12,11 +12,10 @@ import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md` /// See: `normative.md`
describe('components & directives', () => { describe('components & directives', () => {
type $boolean$ = boolean; type $RenderFlags$ = $r3$.ɵRenderFlags;
type $any$ = any; type $any$ = any;
type $number$ = number; type $number$ = number;
it('should instantiate directives', () => { it('should instantiate directives', () => {
type $ChildComponent$ = ChildComponent; type $ChildComponent$ = ChildComponent;
type $MyComponent$ = MyComponent; type $MyComponent$ = MyComponent;
@ -29,9 +28,9 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({ static ngComponentDef = $r3$.ɵdefineComponent({
type: ChildComponent, type: ChildComponent,
selectors: [['child']], selectors: [['child']],
factory: () => new ChildComponent(), factory: function ChildComponent_Factory() { return new ChildComponent(); },
template: function(ctx: $ChildComponent$, cm: $boolean$) { template: function ChildComponent_Template(rf: $RenderFlags$, ctx: $ChildComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵT(0, 'child-view'); $r3$.ɵT(0, 'child-view');
} }
} }
@ -65,8 +64,8 @@ describe('components & directives', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-component']], selectors: [['my-component']],
factory: () => new MyComponent(), factory: () => new MyComponent(),
template: function(ctx: $MyComponent$, cm: $boolean$) { template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'child', $e0_attrs$); $r3$.ɵE(0, 'child', $e0_attrs$);
$r3$.ɵe(); $r3$.ɵe();
$r3$.ɵT(1, '!'); $r3$.ɵT(1, '!');
@ -117,8 +116,8 @@ describe('components & directives', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'div', $e0_attrs$); $r3$.ɵE(0, 'div', $e0_attrs$);
$r3$.ɵe(); $r3$.ɵe();
} }
@ -167,8 +166,8 @@ describe('components & directives', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'button', $e0_attrs$); $r3$.ɵE(0, 'button', $e0_attrs$);
$r3$.ɵT(1, 'Click'); $r3$.ɵT(1, 'Click');
$r3$.ɵe(); $r3$.ɵe();
@ -213,8 +212,8 @@ describe('components & directives', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'div', $e0_attrs$); $r3$.ɵE(0, 'div', $e0_attrs$);
$r3$.ɵe(); $r3$.ɵe();
} }
@ -261,8 +260,8 @@ describe('components & directives', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'div', $e0_attrs$); $r3$.ɵE(0, 'div', $e0_attrs$);
$r3$.ɵe(); $r3$.ɵe();
} }
@ -296,8 +295,8 @@ describe('components & directives', () => {
type: MyComp, type: MyComp,
selectors: [['my-comp']], selectors: [['my-comp']],
factory: function MyComp_Factory() { return new MyComp(); }, factory: function MyComp_Factory() { return new MyComp(); },
template: function MyComp_Template(ctx: $MyComp$, cm: $boolean$) { template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (cm) { if (rf & 1) {
$r3$.ɵT(0); $r3$.ɵT(0);
} }
$r3$.ɵt(0, $r3$.ɵb(ctx.name)); $r3$.ɵt(0, $r3$.ɵb(ctx.name));
@ -321,12 +320,14 @@ describe('components & directives', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'my-comp'); $r3$.ɵE(0, 'my-comp');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp(0, 'name', $r3$.ɵb(ctx.name)); if (rf & 2) {
$r3$.ɵp(0, 'name', $r3$.ɵb(ctx.name));
}
} }
}); });
} }
@ -370,23 +371,27 @@ describe('components & directives', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-component']], selectors: [['my-component']],
factory: () => new MyComponent(), factory: () => new MyComponent(),
template: function(ctx: $MyComponent$, cm: $boolean$) { template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'ul', null, $e0_locals$); $r3$.ɵE(0, 'ul', null, $e0_locals$);
$r3$.ɵC(2, C1, '', ['if', '']); $r3$.ɵC(2, C1, '', ['if', '']);
$r3$.ɵe(); $r3$.ɵe();
} }
let $foo$ = $r3$.ɵld<any>(1); let $foo$ = $r3$.ɵld<any>(1);
$r3$.ɵcR(2); if (rf & 2) {
$r3$.ɵcr(); $r3$.ɵcR(2);
$r3$.ɵcr();
}
function C1(ctx1: $any$, cm: $boolean$) { function C1(rf1: $RenderFlags$, ctx1: $any$) {
if (cm) { if (rf1 & 1) {
$r3$.ɵE(0, 'li'); $r3$.ɵE(0, 'li');
$r3$.ɵT(1); $r3$.ɵT(1);
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵt(1, $r3$.ɵi2('', ctx.salutation, ' ', $foo$, '')); if (rf1 & 2) {
$r3$.ɵt(1, $r3$.ɵi2('', ctx.salutation, ' ', $foo$, ''));
}
} }
} }
}); });
@ -413,11 +418,13 @@ describe('components & directives', () => {
type: MyArrayComp, type: MyArrayComp,
selectors: [['my-array-comp']], selectors: [['my-array-comp']],
factory: function MyArrayComp_Factory() { return new MyArrayComp(); }, factory: function MyArrayComp_Factory() { return new MyArrayComp(); },
template: function MyArrayComp_Template(ctx: $MyArrayComp$, cm: $boolean$) { template: function MyArrayComp_Template(rf: $RenderFlags$, ctx: $MyArrayComp$) {
if (cm) { if (rf & 1) {
$r3$.ɵT(0); $r3$.ɵT(0);
} }
$r3$.ɵt(0, $r3$.ɵi2('', ctx.names[0], ' ', ctx.names[1], '')); if (rf & 2) {
$r3$.ɵt(0, $r3$.ɵi2('', ctx.names[0], ' ', ctx.names[1], ''));
}
}, },
inputs: {names: 'names'} inputs: {names: 'names'}
}); });
@ -442,12 +449,14 @@ describe('components & directives', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'my-array-comp'); $r3$.ɵE(0, 'my-array-comp');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp(0, 'names', cm ? $e0_arr$ : $r3$.ɵNC); if (rf & 2) {
$r3$.ɵp(0, 'names', rf & 1 ? $e0_arr$ : $r3$.ɵNC);
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -484,12 +493,14 @@ describe('components & directives', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'my-array-comp'); $r3$.ɵE(0, 'my-array-comp');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp(0, 'names', $r3$.ɵb(ctx.someFn($r3$.ɵf0($e0_ff$)))); if (rf & 2) {
$r3$.ɵp(0, 'names', $r3$.ɵb(ctx.someFn($r3$.ɵf0($e0_ff$))));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -514,11 +525,13 @@ describe('components & directives', () => {
type: MyComp, type: MyComp,
selectors: [['my-comp']], selectors: [['my-comp']],
factory: function MyComp_Factory() { return new MyComp(); }, factory: function MyComp_Factory() { return new MyComp(); },
template: function MyComp_Template(ctx: $MyComp$, cm: $boolean$) { template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (cm) { if (rf & 1) {
$r3$.ɵT(0); $r3$.ɵT(0);
} }
$r3$.ɵt(0, $r3$.ɵb(ctx.num)); if (rf & 2) {
$r3$.ɵt(0, $r3$.ɵb(ctx.num));
}
}, },
inputs: {num: 'num'} inputs: {num: 'num'}
}); });
@ -540,12 +553,14 @@ describe('components & directives', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'my-comp'); $r3$.ɵE(0, 'my-comp');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp(0, 'num', $r3$.ɵb($r3$.ɵf0($e0_ff$).length + 1)); if (rf & 2) {
$r3$.ɵp(0, 'num', $r3$.ɵb($r3$.ɵf0($e0_ff$).length + 1));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -580,12 +595,14 @@ describe('components & directives', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'my-array-comp'); $r3$.ɵE(0, 'my-array-comp');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp(0, 'names', $r3$.ɵb($r3$.ɵf1($e0_ff$, ctx.customName))); if (rf & 2) {
$r3$.ɵp(0, 'names', $r3$.ɵb($r3$.ɵf1($e0_ff$, ctx.customName)));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -624,8 +641,8 @@ describe('components & directives', () => {
type: MyComp, type: MyComp,
selectors: [['my-comp']], selectors: [['my-comp']],
factory: function MyComp_Factory() { return new MyComp(); }, factory: function MyComp_Factory() { return new MyComp(); },
template: function MyComp_Template(ctx: $MyComp$, cm: $boolean$) { template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (cm) { if (rf & 1) {
$r3$.ɵT(0); $r3$.ɵT(0);
$r3$.ɵT(1); $r3$.ɵT(1);
$r3$.ɵT(2); $r3$.ɵT(2);
@ -639,18 +656,20 @@ describe('components & directives', () => {
$r3$.ɵT(10); $r3$.ɵT(10);
$r3$.ɵT(11); $r3$.ɵT(11);
} }
$r3$.ɵt(0, $r3$.ɵb(ctx.names[0])); if (rf & 2) {
$r3$.ɵt(1, $r3$.ɵb(ctx.names[1])); $r3$.ɵt(0, $r3$.ɵb(ctx.names[0]));
$r3$.ɵt(2, $r3$.ɵb(ctx.names[2])); $r3$.ɵt(1, $r3$.ɵb(ctx.names[1]));
$r3$.ɵt(3, $r3$.ɵb(ctx.names[3])); $r3$.ɵt(2, $r3$.ɵb(ctx.names[2]));
$r3$.ɵt(4, $r3$.ɵb(ctx.names[4])); $r3$.ɵt(3, $r3$.ɵb(ctx.names[3]));
$r3$.ɵt(5, $r3$.ɵb(ctx.names[5])); $r3$.ɵt(4, $r3$.ɵb(ctx.names[4]));
$r3$.ɵt(6, $r3$.ɵb(ctx.names[6])); $r3$.ɵt(5, $r3$.ɵb(ctx.names[5]));
$r3$.ɵt(7, $r3$.ɵb(ctx.names[7])); $r3$.ɵt(6, $r3$.ɵb(ctx.names[6]));
$r3$.ɵt(8, $r3$.ɵb(ctx.names[8])); $r3$.ɵt(7, $r3$.ɵb(ctx.names[7]));
$r3$.ɵt(9, $r3$.ɵb(ctx.names[9])); $r3$.ɵt(8, $r3$.ɵb(ctx.names[8]));
$r3$.ɵt(10, $r3$.ɵb(ctx.names[10])); $r3$.ɵt(9, $r3$.ɵb(ctx.names[9]));
$r3$.ɵt(11, $r3$.ɵb(ctx.names[11])); $r3$.ɵt(10, $r3$.ɵb(ctx.names[10]));
$r3$.ɵt(11, $r3$.ɵb(ctx.names[11]));
}
}, },
inputs: {names: 'names'} inputs: {names: 'names'}
}); });
@ -685,14 +704,17 @@ describe('components & directives', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(c: MyApp, cm: boolean) { template: function MyApp_Template(rf: $RenderFlags$, c: $any$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'my-comp'); $r3$.ɵE(0, 'my-comp');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp( if (rf & 2) {
0, 'names', $r3$.ɵp(
$r3$.ɵb($r3$.ɵfV($e0_ff$, [c.n0, c.n1, c.n2, c.n3, c.n4, c.n5, c.n6, c.n7, c.n8]))); 0, 'names',
$r3$.ɵb(
$r3$.ɵfV($e0_ff$, [c.n0, c.n1, c.n2, c.n3, c.n4, c.n5, c.n6, c.n7, c.n8])));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -723,8 +745,8 @@ describe('components & directives', () => {
type: ObjectComp, type: ObjectComp,
selectors: [['object-comp']], selectors: [['object-comp']],
factory: function ObjectComp_Factory() { return new ObjectComp(); }, factory: function ObjectComp_Factory() { return new ObjectComp(); },
template: function ObjectComp_Template(ctx: $ObjectComp$, cm: $boolean$) { template: function ObjectComp_Template(rf: $RenderFlags$, ctx: $ObjectComp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'p'); $r3$.ɵE(0, 'p');
$r3$.ɵT(1); $r3$.ɵT(1);
$r3$.ɵe(); $r3$.ɵe();
@ -732,8 +754,10 @@ describe('components & directives', () => {
$r3$.ɵT(3); $r3$.ɵT(3);
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵt(1, $r3$.ɵb(ctx.config['duration'])); if (rf & 2) {
$r3$.ɵt(3, $r3$.ɵb(ctx.config.animation)); $r3$.ɵt(1, $r3$.ɵb(ctx.config['duration']));
$r3$.ɵt(3, $r3$.ɵb(ctx.config.animation));
}
}, },
inputs: {config: 'config'} inputs: {config: 'config'}
}); });
@ -757,12 +781,14 @@ describe('components & directives', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'object-comp'); $r3$.ɵE(0, 'object-comp');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp(0, 'config', $r3$.ɵb($r3$.ɵf1($e0_ff$, ctx.name))); if (rf & 2) {
$r3$.ɵp(0, 'config', $r3$.ɵb($r3$.ɵf1($e0_ff$, ctx.name)));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -794,8 +820,8 @@ describe('components & directives', () => {
type: NestedComp, type: NestedComp,
selectors: [['nested-comp']], selectors: [['nested-comp']],
factory: function NestedComp_Factory() { return new NestedComp(); }, factory: function NestedComp_Factory() { return new NestedComp(); },
template: function NestedComp_Template(ctx: $NestedComp$, cm: $boolean$) { template: function NestedComp_Template(rf: $RenderFlags$, ctx: $NestedComp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'p'); $r3$.ɵE(0, 'p');
$r3$.ɵT(1); $r3$.ɵT(1);
$r3$.ɵe(); $r3$.ɵe();
@ -806,9 +832,11 @@ describe('components & directives', () => {
$r3$.ɵT(5); $r3$.ɵT(5);
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵt(1, $r3$.ɵb(ctx.config.animation)); if (rf & 2) {
$r3$.ɵt(3, $r3$.ɵb(ctx.config.actions[0].opacity)); $r3$.ɵt(1, $r3$.ɵb(ctx.config.animation));
$r3$.ɵt(5, $r3$.ɵb(ctx.config.actions[1].duration)); $r3$.ɵt(3, $r3$.ɵb(ctx.config.actions[0].opacity));
$r3$.ɵt(5, $r3$.ɵb(ctx.config.actions[1].duration));
}
}, },
inputs: {config: 'config'} inputs: {config: 'config'}
}); });
@ -837,15 +865,17 @@ describe('components & directives', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'nested-comp'); $r3$.ɵE(0, 'nested-comp');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp( if (rf & 2) {
0, 'config', $r3$.ɵf2( $r3$.ɵp(
$e0_ff_2$, ctx.name, 0, 'config', $r3$.ɵf2(
$r3$.ɵb($r3$.ɵf1($e0_ff_1$, $r3$.ɵf1($e0_ff$, ctx.duration))))); $e0_ff_2$, ctx.name,
$r3$.ɵb($r3$.ɵf1($e0_ff_1$, $r3$.ɵf1($e0_ff$, ctx.duration)))));
}
} }
}); });
// /NORMATIVE // /NORMATIVE

View File

@ -8,11 +8,10 @@
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core'; import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export'; import * as $r3$ from '../../../src/core_render3_private_export';
import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md` /// See: `normative.md`
describe('content projection', () => { describe('content projection', () => {
type $boolean$ = boolean; type $RenderFlags$ = $r3$.ɵRenderFlags;
it('should support content projection', () => { it('should support content projection', () => {
type $SimpleComponent$ = SimpleComponent; type $SimpleComponent$ = SimpleComponent;
@ -26,8 +25,8 @@ describe('content projection', () => {
type: SimpleComponent, type: SimpleComponent,
selectors: [['simple']], selectors: [['simple']],
factory: () => new SimpleComponent(), factory: () => new SimpleComponent(),
template: function(ctx: $SimpleComponent$, cm: $boolean$) { template: function(rf: $RenderFlags$, ctx: $SimpleComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵpD(0); $r3$.ɵpD(0);
$r3$.ɵE(1, 'div'); $r3$.ɵE(1, 'div');
$r3$.ɵP(2, 0); $r3$.ɵP(2, 0);
@ -56,8 +55,8 @@ describe('content projection', () => {
type: ComplexComponent, type: ComplexComponent,
selectors: [['complex']], selectors: [['complex']],
factory: () => new ComplexComponent(), factory: () => new ComplexComponent(),
template: function(ctx: $ComplexComponent$, cm: $boolean$) { template: function(rf: $RenderFlags$, ctx: $ComplexComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵpD(0, $pD_0P$, $pD_0R$); $r3$.ɵpD(0, $pD_0P$, $pD_0R$);
$r3$.ɵE(1, 'div', ['id', 'first']); $r3$.ɵE(1, 'div', ['id', 'first']);
$r3$.ɵP(2, 0, 1); $r3$.ɵP(2, 0, 1);
@ -81,8 +80,8 @@ describe('content projection', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: () => new MyApp(), factory: () => new MyApp(),
template: function(ctx: $MyApp$, cm: $boolean$) { template: function(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'simple'); $r3$.ɵE(0, 'simple');
$r3$.ɵT(1, 'content'); $r3$.ɵT(1, 'content');
$r3$.ɵe(); $r3$.ɵe();

View File

@ -13,10 +13,9 @@ import {ComponentFixture, renderComponent, toHtml} from '../render_util';
/// See: `normative.md` /// See: `normative.md`
describe('elements', () => { describe('elements', () => {
// Saving type as $boolean$, etc to simplify testing for compiler, as types aren't saved // Saving type as $any$, etc to simplify testing for compiler, as types aren't saved
type $boolean$ = boolean;
type $any$ = any; type $any$ = any;
type $number$ = number; type $RenderFlags$ = $r3$.ɵRenderFlags;
it('should translate DOM structure', () => { it('should translate DOM structure', () => {
type $MyComponent$ = MyComponent; type $MyComponent$ = MyComponent;
@ -34,8 +33,8 @@ describe('elements', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-component']], selectors: [['my-component']],
factory: () => new MyComponent(), factory: () => new MyComponent(),
template: function(ctx: $MyComponent$, cm: $boolean$) { template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'div', $e0_attrs$); $r3$.ɵE(0, 'div', $e0_attrs$);
$r3$.ɵT(1, 'Hello '); $r3$.ɵT(1, 'Hello ');
$r3$.ɵE(2, 'b'); $r3$.ɵE(2, 'b');
@ -85,15 +84,19 @@ describe('elements', () => {
type: LocalRefComp, type: LocalRefComp,
selectors: [['local-ref-comp']], selectors: [['local-ref-comp']],
factory: function LocalRefComp_Factory() { return new LocalRefComp(); }, factory: function LocalRefComp_Factory() { return new LocalRefComp(); },
template: function LocalRefComp_Template(ctx: $LocalRefComp$, cm: $boolean$) { template: function LocalRefComp_Template(rf: $RenderFlags$, ctx: $LocalRefComp$) {
if (cm) { let $tmp$: any;
let $tmp_2$: any;
if (rf & 1) {
$r3$.ɵE(0, 'div', $e0_attrs$, $e0_locals$); $r3$.ɵE(0, 'div', $e0_attrs$, $e0_locals$);
$r3$.ɵe(); $r3$.ɵe();
$r3$.ɵT(3); $r3$.ɵT(3);
} }
const $tmp$ = $r3$.ɵld(1) as any; if (rf & 2) {
const $tmp_2$ = $r3$.ɵld(2) as any; $tmp$ = $r3$.ɵld(1);
$r3$.ɵt(3, $r3$.ɵi2(' ', $tmp$.value, ' - ', $tmp_2$.tagName, '')); $tmp_2$ = $r3$.ɵld(2);
$r3$.ɵt(3, $r3$.ɵi2(' ', $tmp$.value, ' - ', $tmp_2$.tagName, ''));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -125,8 +128,8 @@ describe('elements', () => {
type: ListenerComp, type: ListenerComp,
selectors: [['listener-comp']], selectors: [['listener-comp']],
factory: function ListenerComp_Factory() { return new ListenerComp(); }, factory: function ListenerComp_Factory() { return new ListenerComp(); },
template: function ListenerComp_Template(ctx: $ListenerComp$, cm: $boolean$) { template: function ListenerComp_Template(rf: $RenderFlags$, ctx: $ListenerComp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'button'); $r3$.ɵE(0, 'button');
$r3$.ɵL('click', function ListenerComp_click_Handler() { return ctx.onClick(); }); $r3$.ɵL('click', function ListenerComp_click_Handler() { return ctx.onClick(); });
$r3$.ɵL('keypress', function ListenerComp_keypress_Handler($event: $any$) { $r3$.ɵL('keypress', function ListenerComp_keypress_Handler($event: $any$) {
@ -157,12 +160,14 @@ describe('elements', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-component']], selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); }, factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'div'); $r3$.ɵE(0, 'div');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp(0, 'id', $r3$.ɵb(ctx.someProperty)); if (rf & 2) {
$r3$.ɵp(0, 'id', $r3$.ɵb(ctx.someProperty));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -187,12 +192,14 @@ describe('elements', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-component']], selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); }, factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'div'); $r3$.ɵE(0, 'div');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵa(0, 'title', $r3$.ɵb(ctx.someAttribute)); if (rf & 2) {
$r3$.ɵa(0, 'title', $r3$.ɵb(ctx.someAttribute));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -217,12 +224,14 @@ describe('elements', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-component']], selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); }, factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'div'); $r3$.ɵE(0, 'div');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵkn(0, 'foo', $r3$.ɵb(ctx.someFlag)); if (rf & 2) {
$r3$.ɵkn(0, 'foo', $r3$.ɵb(ctx.someFlag));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -251,13 +260,15 @@ describe('elements', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-component']], selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); }, factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'div'); $r3$.ɵE(0, 'div');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵsn(0, 'color', $r3$.ɵb(ctx.someColor)); if (rf & 2) {
$r3$.ɵsn(0, 'width', $r3$.ɵb(ctx.someWidth), 'px'); $r3$.ɵsn(0, 'color', $r3$.ɵb(ctx.someColor));
$r3$.ɵsn(0, 'width', $r3$.ɵb(ctx.someWidth), 'px');
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -299,13 +310,15 @@ describe('elements', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-component']], selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); }, factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'div', $e0_attrs$); $r3$.ɵE(0, 'div', $e0_attrs$);
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp(0, 'id', $r3$.ɵb(ctx.someString + 1)); if (rf & 2) {
$r3$.ɵkn(0, 'foo', $r3$.ɵb(ctx.someString == 'initial')); $r3$.ɵp(0, 'id', $r3$.ɵb(ctx.someString + 1));
$r3$.ɵkn(0, 'foo', $r3$.ɵb(ctx.someString == 'initial'));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -333,13 +346,15 @@ describe('elements', () => {
type: StyleComponent, type: StyleComponent,
selectors: [['style-comp']], selectors: [['style-comp']],
factory: function StyleComponent_Factory() { return new StyleComponent(); }, factory: function StyleComponent_Factory() { return new StyleComponent(); },
template: function StyleComponent_Template(ctx: $StyleComponent$, cm: $boolean$) { template: function StyleComponent_Template(rf: $RenderFlags$, ctx: $StyleComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'div'); $r3$.ɵE(0, 'div');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵk(0, $r3$.ɵb(ctx.classExp)); if (rf & 2) {
$r3$.ɵs(0, $r3$.ɵb(ctx.styleExp)); $r3$.ɵk(0, $r3$.ɵb(ctx.classExp));
$r3$.ɵs(0, $r3$.ɵb(ctx.styleExp));
}
} }
}); });
// /NORMATIVE // /NORMATIVE

View File

@ -14,7 +14,7 @@ import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md` /// See: `normative.md`
describe('injection', () => { describe('injection', () => {
type $boolean$ = boolean; type $RenderFlags$ = $r3$.ɵRenderFlags;
describe('directives', () => { describe('directives', () => {
// Directives (and Components) should use `directiveInject` // Directives (and Components) should use `directiveInject`
@ -34,11 +34,13 @@ describe('injection', () => {
factory: function MyComp_Factory() { factory: function MyComp_Factory() {
return new MyComp($r3$.ɵinjectChangeDetectorRef()); return new MyComp($r3$.ɵinjectChangeDetectorRef());
}, },
template: function MyComp_Template(ctx: $MyComp$, cm: $boolean$) { template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (cm) { if (rf & 1) {
$r3$.ɵT(0); $r3$.ɵT(0);
} }
$r3$.ɵt(0, $r3$.ɵb(ctx.value)); if (rf & 2) {
$r3$.ɵt(0, $r3$.ɵb(ctx.value));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -50,8 +52,8 @@ describe('injection', () => {
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
/** <my-comp></my-comp> */ /** <my-comp></my-comp> */
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'my-comp'); $r3$.ɵE(0, 'my-comp');
$r3$.ɵe(); $r3$.ɵe();
} }
@ -79,11 +81,13 @@ describe('injection', () => {
type: MyComp, type: MyComp,
selectors: [['my-comp']], selectors: [['my-comp']],
factory: function MyComp_Factory() { return new MyComp($r3$.ɵinjectAttribute('title')); }, factory: function MyComp_Factory() { return new MyComp($r3$.ɵinjectAttribute('title')); },
template: function MyComp_Template(ctx: $MyComp$, cm: $boolean$) { template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (cm) { if (rf & 1) {
$r3$.ɵT(0); $r3$.ɵT(0);
} }
$r3$.ɵt(0, $r3$.ɵb(ctx.title)); if (rf & 2) {
$r3$.ɵt(0, $r3$.ɵb(ctx.title));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -95,8 +99,8 @@ describe('injection', () => {
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
/** <my-comp></my-comp> */ /** <my-comp></my-comp> */
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'my-comp', e0_attrs); $r3$.ɵE(0, 'my-comp', e0_attrs);
$r3$.ɵe(); $r3$.ɵe();
} }
@ -148,7 +152,7 @@ describe('injection', () => {
$r3$.ɵdirectiveInject(ServiceA), $r3$.ɵdirectiveInject(ServiceB), inject(INJECTOR)); $r3$.ɵdirectiveInject(ServiceA), $r3$.ɵdirectiveInject(ServiceB), inject(INJECTOR));
}, },
/** */ /** */
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) {}, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {},
providers: [ServiceA], providers: [ServiceA],
viewProviders: [ServiceB], viewProviders: [ServiceB],
}); });

View File

@ -15,7 +15,7 @@ describe('lifecycle hooks', () => {
let events: string[] = []; let events: string[] = [];
let simpleLayout: SimpleLayout; let simpleLayout: SimpleLayout;
type $boolean$ = boolean; type $RenderFlags$ = $r3$.ɵRenderFlags;
type $LifecycleComp$ = LifecycleComp; type $LifecycleComp$ = LifecycleComp;
type $SimpleLayout$ = SimpleLayout; type $SimpleLayout$ = SimpleLayout;
@ -43,7 +43,7 @@ describe('lifecycle hooks', () => {
type: LifecycleComp, type: LifecycleComp,
selectors: [['lifecycle-comp']], selectors: [['lifecycle-comp']],
factory: function LifecycleComp_Factory() { return new LifecycleComp(); }, factory: function LifecycleComp_Factory() { return new LifecycleComp(); },
template: function LifecycleComp_Template(ctx: $LifecycleComp$, cm: $boolean$) {}, template: function LifecycleComp_Template(rf: $RenderFlags$, ctx: $LifecycleComp$) {},
inputs: {nameMin: 'name'}, inputs: {nameMin: 'name'},
features: [$r3$.ɵNgOnChangesFeature({nameMin: 'nameMin'})] features: [$r3$.ɵNgOnChangesFeature({nameMin: 'nameMin'})]
}); });
@ -66,15 +66,17 @@ describe('lifecycle hooks', () => {
type: SimpleLayout, type: SimpleLayout,
selectors: [['simple-layout']], selectors: [['simple-layout']],
factory: function SimpleLayout_Factory() { return simpleLayout = new SimpleLayout(); }, factory: function SimpleLayout_Factory() { return simpleLayout = new SimpleLayout(); },
template: function SimpleLayout_Template(ctx: $SimpleLayout$, cm: $boolean$) { template: function SimpleLayout_Template(rf: $RenderFlags$, ctx: $SimpleLayout$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'lifecycle-comp'); $r3$.ɵE(0, 'lifecycle-comp');
$r3$.ɵe(); $r3$.ɵe();
$r3$.ɵE(1, 'lifecycle-comp'); $r3$.ɵE(1, 'lifecycle-comp');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp(0, 'name', $r3$.ɵb(ctx.name1)); if (rf & 2) {
$r3$.ɵp(1, 'name', $r3$.ɵb(ctx.name2)); $r3$.ɵp(0, 'name', $r3$.ɵb(ctx.name1));
$r3$.ɵp(1, 'name', $r3$.ɵb(ctx.name2));
}
} }
}); });
// /NORMATIVE // /NORMATIVE

View File

@ -12,7 +12,7 @@ import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md` /// See: `normative.md`
describe('local references', () => { describe('local references', () => {
type $boolean$ = boolean; type $RenderFlags$ = $r3$.ɵRenderFlags;
// TODO(misko): currently disabled until local refs are working // TODO(misko): currently disabled until local refs are working
xit('should translate DOM structure', () => { xit('should translate DOM structure', () => {
@ -25,14 +25,17 @@ describe('local references', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-component']], selectors: [['my-component']],
factory: () => new MyComponent, factory: () => new MyComponent,
template: function(ctx: $MyComponent$, cm: $boolean$) { template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
if (cm) { let l1_user: any;
if (rf & 1) {
$r3$.ɵE(0, 'input', null, ['user', '']); $r3$.ɵE(0, 'input', null, ['user', '']);
$r3$.ɵe(); $r3$.ɵe();
$r3$.ɵT(2); $r3$.ɵT(2);
} }
const l1_user = $r3$.ɵld<any>(1); if (rf & 2) {
$r3$.ɵt(2, $r3$.ɵi1('Hello ', l1_user.value, '!')); l1_user = $r3$.ɵld<any>(1);
$r3$.ɵt(2, $r3$.ɵi1('Hello ', l1_user.value, '!'));
}
} }
}); });
// NORMATIVE // NORMATIVE

View File

@ -13,7 +13,7 @@ import {containerEl, renderComponent, toHtml} from '../render_util';
/// See: `normative.md` /// See: `normative.md`
describe('pipes', () => { describe('pipes', () => {
type $any$ = any; type $any$ = any;
type $boolean$ = boolean; type $RenderFlags$ = $r3$.ɵRenderFlags;
let myPipeTransformCalls = 0; let myPipeTransformCalls = 0;
let myPurePipeTransformCalls = 0; let myPurePipeTransformCalls = 0;
@ -81,13 +81,15 @@ describe('pipes', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵT(0); $r3$.ɵT(0);
$r3$.ɵPp(1, 'myPipe'); $r3$.ɵPp(1, 'myPipe');
$r3$.ɵPp(2, 'myPurePipe'); $r3$.ɵPp(2, 'myPurePipe');
} }
$r3$.ɵt(0, $r3$.ɵi1('', $r3$.ɵpb2(1, $r3$.ɵpb2(2, ctx.name, ctx.size), ctx.size), '')); if (rf & 2) {
$r3$.ɵt(0, $r3$.ɵi1('', $r3$.ɵpb2(1, $r3$.ɵpb2(2, ctx.name, ctx.size), ctx.size), ''));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -154,28 +156,32 @@ describe('pipes', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵT(0); $r3$.ɵT(0);
$r3$.ɵPp(1, 'myPurePipe'); $r3$.ɵPp(1, 'myPurePipe');
$r3$.ɵT(2); $r3$.ɵT(2);
$r3$.ɵPp(3, 'myPurePipe'); $r3$.ɵPp(3, 'myPurePipe');
$r3$.ɵC(4, C4, '', ['oneTimeIf', '']); $r3$.ɵC(4, C4, '', ['oneTimeIf', '']);
} }
$r3$.ɵt(0, $r3$.ɵi1('', $r3$.ɵpb2(1, ctx.name, ctx.size), '')); if (rf & 2) {
$r3$.ɵt(2, $r3$.ɵi1('', $r3$.ɵpb2(3, ctx.name, ctx.size), '')); $r3$.ɵt(0, $r3$.ɵi1('', $r3$.ɵpb2(1, ctx.name, ctx.size), ''));
$r3$.ɵp(4, 'oneTimeIf', $r3$.ɵb(ctx.more)); $r3$.ɵt(2, $r3$.ɵi1('', $r3$.ɵpb2(3, ctx.name, ctx.size), ''));
$r3$.ɵcR(4); $r3$.ɵp(4, 'oneTimeIf', $r3$.ɵb(ctx.more));
$r3$.ɵcr(); $r3$.ɵcR(4);
$r3$.ɵcr();
}
function C4(ctx1: $any$, cm: $boolean$) { function C4(rf: $RenderFlags$, ctx1: $any$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'div'); $r3$.ɵE(0, 'div');
$r3$.ɵT(1); $r3$.ɵT(1);
$r3$.ɵPp(2, 'myPurePipe'); $r3$.ɵPp(2, 'myPurePipe');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵt(1, $r3$.ɵi1('', $r3$.ɵpb2(2, ctx.name, ctx.size), '')); if (rf & 2) {
$r3$.ɵt(1, $r3$.ɵi1('', $r3$.ɵpb2(2, ctx.name, ctx.size), ''));
}
} }
} }
}); });

View File

@ -12,7 +12,7 @@ import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md` /// See: `normative.md`
describe('queries', () => { describe('queries', () => {
type $boolean$ = boolean; type $RenderFlags$ = $r3$.ɵRenderFlags;
type $number$ = number; type $number$ = number;
let someDir: SomeDirective; let someDir: SomeDirective;
@ -50,18 +50,20 @@ describe('queries', () => {
type: ViewQueryComponent, type: ViewQueryComponent,
selectors: [['view-query-component']], selectors: [['view-query-component']],
factory: function ViewQueryComponent_Factory() { return new ViewQueryComponent(); }, factory: function ViewQueryComponent_Factory() { return new ViewQueryComponent(); },
template: function ViewQueryComponent_Template(ctx: $ViewQueryComponent$, cm: $boolean$) { template: function ViewQueryComponent_Template(
rf: $RenderFlags$, ctx: $ViewQueryComponent$) {
let $tmp$: any; let $tmp$: any;
if (cm) { if (rf & 1) {
$r3$.ɵQ(0, SomeDirective, false); $r3$.ɵQ(0, SomeDirective, false);
$r3$.ɵQ(1, SomeDirective, false); $r3$.ɵQ(1, SomeDirective, false);
$r3$.ɵE(2, 'div', $e1_attrs$); $r3$.ɵE(2, 'div', $e1_attrs$);
$r3$.ɵe(); $r3$.ɵe();
} }
if (rf & 2) {
$r3$.ɵqR($tmp$ = $r3$.ɵld<QueryList<any>>(0)) && (ctx.someDir = $tmp$.first); $r3$.ɵqR($tmp$ = $r3$.ɵld<QueryList<any>>(0)) && (ctx.someDir = $tmp$.first);
$r3$.ɵqR($tmp$ = $r3$.ɵld<QueryList<any>>(1)) && $r3$.ɵqR($tmp$ = $r3$.ɵld<QueryList<any>>(1)) &&
(ctx.someDirList = $tmp$ as QueryList<any>); (ctx.someDirList = $tmp$ as QueryList<any>);
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -110,8 +112,8 @@ describe('queries', () => {
$r3$.ɵqR($tmp$ = $r3$.ɵd<any[]>(dirIndex)[2]) && ($instance$.someDirList = $tmp$); $r3$.ɵqR($tmp$ = $r3$.ɵd<any[]>(dirIndex)[2]) && ($instance$.someDirList = $tmp$);
}, },
template: function ContentQueryComponent_Template( template: function ContentQueryComponent_Template(
ctx: $ContentQueryComponent$, cm: $boolean$) { rf: $number$, ctx: $ContentQueryComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵpD(0); $r3$.ɵpD(0);
$r3$.ɵE(1, 'div'); $r3$.ɵE(1, 'div');
$r3$.ɵP(2, 0); $r3$.ɵP(2, 0);
@ -138,8 +140,8 @@ describe('queries', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); }, factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'content-query-component'); $r3$.ɵE(0, 'content-query-component');
contentQueryComp = $r3$.ɵd<any[]>(0)[0]; contentQueryComp = $r3$.ɵd<any[]>(0)[0];
$r3$.ɵE(1, 'div', $e2_attrs$); $r3$.ɵE(1, 'div', $e2_attrs$);

View File

@ -19,7 +19,8 @@ import {renderComponent, toHtml} from '../render_util';
*/ */
describe('compiler sanitization', () => { describe('compiler sanitization', () => {
type $boolean$ = boolean; type $RenderFlags$ = $r3$.ɵRenderFlags;
it('should translate DOM structure', () => { it('should translate DOM structure', () => {
type $MyComponent$ = MyComponent; type $MyComponent$ = MyComponent;
@ -40,18 +41,20 @@ describe('compiler sanitization', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-component']], selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); }, factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'div'); $r3$.ɵE(0, 'div');
$r3$.ɵe(); $r3$.ɵe();
$r3$.ɵE(1, 'img'); $r3$.ɵE(1, 'img');
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp(0, 'innerHTML', $r3$.ɵb(ctx.innerHTML), $r3$.ɵsanitizeHtml); if (rf & 2) {
$r3$.ɵp(0, 'hidden', $r3$.ɵb(ctx.hidden)); $r3$.ɵp(0, 'innerHTML', $r3$.ɵb(ctx.innerHTML), $r3$.ɵsanitizeHtml);
$r3$.ɵsn(1, 'background-image', $r3$.ɵb(ctx.style), $r3$.ɵsanitizeStyle); $r3$.ɵp(0, 'hidden', $r3$.ɵb(ctx.hidden));
$r3$.ɵp(1, 'src', $r3$.ɵb(ctx.url), $r3$.ɵsanitizeUrl); $r3$.ɵsn(1, 'background-image', $r3$.ɵb(ctx.style), $r3$.ɵsanitizeStyle);
$r3$.ɵa(1, 'srcset', $r3$.ɵb(ctx.url), $r3$.ɵsanitizeUrl); $r3$.ɵp(1, 'src', $r3$.ɵb(ctx.url), $r3$.ɵsanitizeUrl);
$r3$.ɵa(1, 'srcset', $r3$.ɵb(ctx.url), $r3$.ɵsanitizeUrl);
}
} }
}); });
// /NORMATIVE // /NORMATIVE

View File

@ -21,6 +21,8 @@ interface ToDo {
done: boolean; done: boolean;
} }
type $RenderFlags$ = r3.RenderFlags;
@Injectable() @Injectable()
class AppState { class AppState {
todos: ToDo[] = [ todos: ToDo[] = [
@ -62,16 +64,18 @@ class ToDoAppComponent {
factory: function ToDoAppComponent_Factory() { factory: function ToDoAppComponent_Factory() {
return new ToDoAppComponent(r3.directiveInject(AppState)); return new ToDoAppComponent(r3.directiveInject(AppState));
}, },
template: function ToDoAppComponent_Template(ctx: ToDoAppComponent, cm: boolean) { template: function ToDoAppComponent_Template(rf: $RenderFlags$, ctx: ToDoAppComponent) {
if (cm) { if (rf & 1) {
const ToDoAppComponent_NgForOf_Template = function ToDoAppComponent_NgForOf_Template( const ToDoAppComponent_NgForOf_Template = function ToDoAppComponent_NgForOf_Template(
ctx1: NgForOfContext<ToDo>, cm: boolean) { rf: $RenderFlags$, ctx1: NgForOfContext<ToDo>) {
if (cm) { if (rf & 1) {
r3.E(0, 'todo'); r3.E(0, 'todo');
r3.L('archive', ctx.onArchive.bind(ctx)); r3.L('archive', ctx.onArchive.bind(ctx));
r3.e(); r3.e();
} }
r3.p(0, 'todo', r3.b(ctx1.$implicit)); if (rf & 2) {
r3.p(0, 'todo', r3.b(ctx1.$implicit));
}
}; };
r3.E(0, 'h1'); r3.E(0, 'h1');
r3.T(1, 'ToDo Application'); r3.T(1, 'ToDo Application');
@ -83,7 +87,9 @@ class ToDoAppComponent {
r3.T(5); r3.T(5);
r3.e(); r3.e();
} }
r3.t(5, r3.i1('count: ', ctx.appState.todos.length, '')); if (rf & 2) {
r3.t(5, r3.i1('count: ', ctx.appState.todos.length, ''));
}
} }
}); });
// /NORMATIVE // /NORMATIVE
@ -125,8 +131,8 @@ class ToDoItemComponent {
type: ToDoItemComponent, type: ToDoItemComponent,
selectors: [['todo']], selectors: [['todo']],
factory: function ToDoItemComponent_Factory() { return new ToDoItemComponent(); }, factory: function ToDoItemComponent_Factory() { return new ToDoItemComponent(); },
template: function ToDoItemComponent_Template(ctx: ToDoItemComponent, cm: boolean) { template: function ToDoItemComponent_Template(rf: $RenderFlags$, ctx: ToDoItemComponent) {
if (cm) { if (rf & 1) {
r3.E(0, 'div'); r3.E(0, 'div');
r3.E(1, 'input', e1_attrs); r3.E(1, 'input', e1_attrs);
r3.L('click', ctx.onCheckboxClick.bind(ctx)); r3.L('click', ctx.onCheckboxClick.bind(ctx));
@ -140,8 +146,10 @@ class ToDoItemComponent {
r3.e(); r3.e();
r3.e(); r3.e();
} }
r3.p(1, 'value', r3.b(ctx.todo.done)); if (rf & 2) {
r3.t(3, r3.b(ctx.todo.text)); r3.p(1, 'value', r3.b(ctx.todo.done));
r3.t(3, r3.b(ctx.todo.text));
}
}, },
inputs: {todo: 'todo'}, inputs: {todo: 'todo'},
}); });

View File

@ -12,9 +12,9 @@ import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md` /// See: `normative.md`
describe('template variables', () => { describe('template variables', () => {
type $boolean$ = boolean;
type $any$ = any; type $any$ = any;
type $number$ = number; type $number$ = number;
type $RenderFlags$ = $r3$.ɵRenderFlags;
interface ForOfContext { interface ForOfContext {
$implicit: any; $implicit: any;
@ -93,24 +93,29 @@ describe('template variables', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-component']], selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); }, factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'ul'); $r3$.ɵE(0, 'ul');
$r3$.ɵC(1, MyComponent_ForOfDirective_Template_1, '', ['forOf', '']); $r3$.ɵC(1, MyComponent_ForOfDirective_Template_1, '', ['forOf', '']);
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp(1, 'forOf', $r3$.ɵb(ctx.items)); if (rf & 2) {
$r3$.ɵcR(1); $r3$.ɵp(1, 'forOf', $r3$.ɵb(ctx.items));
$r3$.ɵcr(); $r3$.ɵcR(1);
$r3$.ɵcr();
}
function MyComponent_ForOfDirective_Template_1(ctx1: $any$, cm: $boolean$) { function MyComponent_ForOfDirective_Template_1(rf: $RenderFlags$, ctx1: $any$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'li'); $r3$.ɵE(0, 'li');
$r3$.ɵT(1); $r3$.ɵT(1);
$r3$.ɵe(); $r3$.ɵe();
} }
const $l0_item$ = ctx1.$implicit; let $l0_item$: any;
$r3$.ɵt(1, $r3$.ɵi1('', $l0_item$.name, '')); if (rf & 2) {
$l0_item$ = ctx1.$implicit;
$r3$.ɵt(1, $r3$.ɵi1('', $l0_item$.name, ''));
}
} }
} }
}); });
@ -161,18 +166,20 @@ describe('template variables', () => {
type: MyComponent, type: MyComponent,
selectors: [['my-component']], selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); }, factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'ul'); $r3$.ɵE(0, 'ul');
$r3$.ɵC(1, MyComponent_ForOfDirective_Template_1, '', ['forOf', '']); $r3$.ɵC(1, MyComponent_ForOfDirective_Template_1, '', ['forOf', '']);
$r3$.ɵe(); $r3$.ɵe();
} }
$r3$.ɵp(1, 'forOf', $r3$.ɵb(ctx.items)); if (rf & 2) {
$r3$.ɵcR(1); $r3$.ɵp(1, 'forOf', $r3$.ɵb(ctx.items));
$r3$.ɵcr(); $r3$.ɵcR(1);
$r3$.ɵcr();
}
function MyComponent_ForOfDirective_Template_1(ctx1: $any$, cm: $boolean$) { function MyComponent_ForOfDirective_Template_1(rf1: $RenderFlags$, ctx1: $any$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'li'); $r3$.ɵE(0, 'li');
$r3$.ɵE(1, 'div'); $r3$.ɵE(1, 'div');
$r3$.ɵT(2); $r3$.ɵT(2);
@ -182,21 +189,27 @@ describe('template variables', () => {
$r3$.ɵe(); $r3$.ɵe();
$r3$.ɵe(); $r3$.ɵe();
} }
const $l0_item$ = ctx1.$implicit; let $l0_item$: any;
$r3$.ɵp(4, 'forOf', $r3$.ɵb($l0_item$.infos)); if (rf & 2) {
$r3$.ɵt(2, $r3$.ɵi1('', $l0_item$.name, '')); $l0_item$ = ctx1.$implicit;
$r3$.ɵcR(4); $r3$.ɵp(4, 'forOf', $r3$.ɵb($l0_item$.infos));
$r3$.ɵcr(); $r3$.ɵt(2, $r3$.ɵi1('', $l0_item$.name, ''));
$r3$.ɵcR(4);
$r3$.ɵcr();
}
function MyComponent_ForOfDirective_ForOfDirective_Template_3( function MyComponent_ForOfDirective_ForOfDirective_Template_3(
ctx2: $any$, cm: $boolean$) { rf2: $number$, ctx2: $any$) {
if (cm) { if (rf & 1) {
$r3$.ɵE(0, 'li'); $r3$.ɵE(0, 'li');
$r3$.ɵT(1); $r3$.ɵT(1);
$r3$.ɵe(); $r3$.ɵe();
} }
const $l0_info$ = ctx2.$implicit; let $l0_info$: any;
$r3$.ɵt(1, $r3$.ɵi2(' ', $l0_item$.name, ': ', $l0_info$.description, ' ')); if (rf & 2) {
$l0_info$ = ctx2.$implicit;
$r3$.ɵt(1, $r3$.ɵi2(' ', $l0_item$.name, ': ', $l0_info$.description, ' '));
}
} }
} }
} }

View File

@ -11,6 +11,7 @@ import {DoCheck, ViewEncapsulation} from '../../src/core';
import {getRenderedText} from '../../src/render3/component'; import {getRenderedText} from '../../src/render3/component';
import {LifecycleHooksFeature, defineComponent, markDirty} from '../../src/render3/index'; import {LifecycleHooksFeature, defineComponent, markDirty} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, text, textBinding, tick} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, text, textBinding, tick} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {createRendererType2} from '../../src/view/index'; import {createRendererType2} from '../../src/view/index';
import {getRendererFactory2} from './imported_renderer2'; import {getRendererFactory2} from './imported_renderer2';
@ -25,11 +26,13 @@ describe('component', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: CounterComponent, type: CounterComponent,
selectors: [['counter']], selectors: [['counter']],
template: function(ctx: CounterComponent, cm: boolean) { template: function(rf: RenderFlags, ctx: CounterComponent) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, bind(ctx.count)); if (rf & RenderFlags.Update) {
textBinding(0, bind(ctx.count));
}
}, },
factory: () => new CounterComponent, factory: () => new CounterComponent,
inputs: {count: 'count'}, inputs: {count: 'count'},
@ -63,24 +66,28 @@ describe('component', () => {
describe('component with a container', () => { describe('component with a container', () => {
function showItems(ctx: {items: string[]}, cm: boolean) { function showItems(rf: RenderFlags, ctx: {items: string[]}) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
for (const item of ctx.items) { {
const cm0 = embeddedViewStart(0); for (const item of ctx.items) {
{ const rf0 = embeddedViewStart(0);
if (cm0) { {
text(0); if (rf0 & RenderFlags.Create) {
text(0);
}
if (rf0 & RenderFlags.Update) {
textBinding(0, bind(item));
}
} }
textBinding(0, bind(item)); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
class WrapperComponent { class WrapperComponent {
@ -88,29 +95,33 @@ describe('component with a container', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: WrapperComponent, type: WrapperComponent,
selectors: [['wrapper']], selectors: [['wrapper']],
template: function ChildComponentTemplate(ctx: {items: string[]}, cm: boolean) { template: function ChildComponentTemplate(rf: RenderFlags, ctx: {items: string[]}) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
const cm0 = embeddedViewStart(0); {
{ showItems({items: ctx.items}, cm0); } const rf0 = embeddedViewStart(0);
embeddedViewEnd(); { showItems(rf0, {items: ctx.items}); }
embeddedViewEnd();
}
containerRefreshEnd();
} }
containerRefreshEnd();
}, },
factory: () => new WrapperComponent, factory: () => new WrapperComponent,
inputs: {items: 'items'} inputs: {items: 'items'}
}); });
} }
function template(ctx: {items: string[]}, cm: boolean) { function template(rf: RenderFlags, ctx: {items: string[]}) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'wrapper'); elementStart(0, 'wrapper');
elementEnd(); elementEnd();
} }
elementProperty(0, 'items', bind(ctx.items)); if (rf & RenderFlags.Update) {
elementProperty(0, 'items', bind(ctx.items));
}
} }
const defs = [WrapperComponent]; const defs = [WrapperComponent];
@ -132,8 +143,8 @@ describe('encapsulation', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: WrapperComponent, type: WrapperComponent,
selectors: [['wrapper']], selectors: [['wrapper']],
template: function(ctx: WrapperComponent, cm: boolean) { template: function(rf: RenderFlags, ctx: WrapperComponent) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'encapsulated'); elementStart(0, 'encapsulated');
elementEnd(); elementEnd();
} }
@ -147,8 +158,8 @@ describe('encapsulation', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: EncapsulatedComponent, type: EncapsulatedComponent,
selectors: [['encapsulated']], selectors: [['encapsulated']],
template: function(ctx: EncapsulatedComponent, cm: boolean) { template: function(rf: RenderFlags, ctx: EncapsulatedComponent) {
if (cm) { if (rf & RenderFlags.Create) {
text(0, 'foo'); text(0, 'foo');
elementStart(1, 'leaf'); elementStart(1, 'leaf');
elementEnd(); elementEnd();
@ -165,8 +176,8 @@ describe('encapsulation', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: LeafComponent, type: LeafComponent,
selectors: [['leaf']], selectors: [['leaf']],
template: function(ctx: LeafComponent, cm: boolean) { template: function(rf: RenderFlags, ctx: LeafComponent) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
{ text(1, 'bar'); } { text(1, 'bar'); }
elementEnd(); elementEnd();
@ -195,8 +206,8 @@ describe('encapsulation', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: WrapperComponentWith, type: WrapperComponentWith,
selectors: [['wrapper']], selectors: [['wrapper']],
template: function(ctx: WrapperComponentWith, cm: boolean) { template: function(rf: RenderFlags, ctx: WrapperComponentWith) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'leaf'); elementStart(0, 'leaf');
elementEnd(); elementEnd();
} }
@ -212,8 +223,8 @@ describe('encapsulation', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: LeafComponentwith, type: LeafComponentwith,
selectors: [['leaf']], selectors: [['leaf']],
template: function(ctx: LeafComponentwith, cm: boolean) { template: function(rf: RenderFlags, ctx: LeafComponentwith) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
{ text(1, 'bar'); } { text(1, 'bar'); }
elementEnd(); elementEnd();
@ -252,37 +263,45 @@ describe('recursive components', () => {
type: TreeComponent, type: TreeComponent,
selectors: [['tree-comp']], selectors: [['tree-comp']],
factory: () => new TreeComponent(), factory: () => new TreeComponent(),
template: (ctx: TreeComponent, cm: boolean) => { template: (rf: RenderFlags, ctx: TreeComponent) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
container(1); container(1);
container(2); container(2);
} }
textBinding(0, bind(ctx.data.value)); if (rf & RenderFlags.Update) {
containerRefreshStart(1); textBinding(0, bind(ctx.data.value));
{ containerRefreshStart(1);
if (ctx.data.left != null) { {
if (embeddedViewStart(0)) { if (ctx.data.left != null) {
elementStart(0, 'tree-comp'); let rf0 = embeddedViewStart(0);
elementEnd(); if (rf0 & RenderFlags.Create) {
elementStart(0, 'tree-comp');
elementEnd();
}
if (rf0 & RenderFlags.Update) {
elementProperty(0, 'data', bind(ctx.data.left));
}
embeddedViewEnd();
} }
elementProperty(0, 'data', bind(ctx.data.left));
embeddedViewEnd();
} }
} containerRefreshEnd();
containerRefreshEnd(); containerRefreshStart(2);
containerRefreshStart(2); {
{ if (ctx.data.right != null) {
if (ctx.data.right != null) { let rf0 = embeddedViewStart(0);
if (embeddedViewStart(0)) { if (rf0 & RenderFlags.Create) {
elementStart(0, 'tree-comp'); elementStart(0, 'tree-comp');
elementEnd(); elementEnd();
}
if (rf0 & RenderFlags.Update) {
elementProperty(0, 'data', bind(ctx.data.right));
}
embeddedViewEnd();
} }
elementProperty(0, 'data', bind(ctx.data.right));
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}, },
inputs: {data: 'data'} inputs: {data: 'data'}
}); });

View File

@ -10,7 +10,7 @@ import {SelectorFlags} from '@angular/core/src/render3/interfaces/projection';
import {detectChanges} from '../../src/render3/index'; import {detectChanges} from '../../src/render3/index';
import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective, projection, projectionDef, text} from '../../src/render3/instructions'; import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective, projection, projectionDef, text} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {createComponent, renderComponent, toHtml} from './render_util'; import {createComponent, renderComponent, toHtml} from './render_util';
describe('content projection', () => { describe('content projection', () => {
@ -19,8 +19,8 @@ describe('content projection', () => {
/** /**
* <div><ng-content></ng-content></div> * <div><ng-content></ng-content></div>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'div'); elementStart(1, 'div');
{ projection(2, 0); } { projection(2, 0); }
@ -31,8 +31,8 @@ describe('content projection', () => {
/** /**
* <child>content</child> * <child>content</child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ text(1, 'content'); } { text(1, 'content'); }
elementEnd(); elementEnd();
@ -44,14 +44,14 @@ describe('content projection', () => {
}); });
it('should project content when root.', () => { it('should project content when root.', () => {
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
projection(1, 0); projection(1, 0);
} }
}); });
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ text(1, 'content'); } { text(1, 'content'); }
elementEnd(); elementEnd();
@ -63,24 +63,24 @@ describe('content projection', () => {
}); });
it('should re-project content when root.', () => { it('should re-project content when root.', () => {
const GrandChild = createComponent('grand-child', function(ctx: any, cm: boolean) { const GrandChild = createComponent('grand-child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'div'); elementStart(1, 'div');
{ projection(2, 0); } { projection(2, 0); }
elementEnd(); elementEnd();
} }
}); });
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'grand-child'); elementStart(1, 'grand-child');
{ projection(2, 0); } { projection(2, 0); }
elementEnd(); elementEnd();
} }
}, [GrandChild]); }, [GrandChild]);
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
elementStart(1, 'b'); elementStart(1, 'b');
@ -100,8 +100,8 @@ describe('content projection', () => {
it('should project components', () => { it('should project components', () => {
/** <div><ng-content></ng-content></div> */ /** <div><ng-content></ng-content></div> */
const Child = createComponent('child', (ctx: any, cm: boolean) => { const Child = createComponent('child', (rf: RenderFlags, ctx: any) => {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'div'); elementStart(1, 'div');
{ projection(2, 0); } { projection(2, 0); }
@ -109,8 +109,8 @@ describe('content projection', () => {
} }
}); });
const ProjectedComp = createComponent('projected-comp', (ctx: any, cm: boolean) => { const ProjectedComp = createComponent('projected-comp', (rf: RenderFlags, ctx: any) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0, 'content'); text(0, 'content');
} }
}); });
@ -120,8 +120,8 @@ describe('content projection', () => {
* <projected-comp></projected-comp> * <projected-comp></projected-comp>
* </child> * </child>
*/ */
const Parent = createComponent('parent', (ctx: any, cm: boolean) => { const Parent = createComponent('parent', (rf: RenderFlags, ctx: any) => {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
elementStart(1, 'projected-comp'); elementStart(1, 'projected-comp');
@ -137,16 +137,16 @@ describe('content projection', () => {
}); });
it('should project content with container.', () => { it('should project content with container.', () => {
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'div'); elementStart(1, 'div');
{ projection(2, 0); } { projection(2, 0); }
elementEnd(); elementEnd();
} }
}); });
const Parent = createComponent('parent', function(ctx: {value: any}, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: {value: any}) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
text(1, '('); text(1, '(');
@ -155,16 +155,19 @@ describe('content projection', () => {
} }
elementEnd(); elementEnd();
} }
containerRefreshStart(2); if (rf & RenderFlags.Update) {
{ containerRefreshStart(2);
if (ctx.value) { {
if (embeddedViewStart(0)) { if (ctx.value) {
text(0, 'content'); let rf0 = embeddedViewStart(0);
if (rf0 & RenderFlags.Create) {
text(0, 'content');
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}, [Child]); }, [Child]);
const parent = renderComponent(Parent); const parent = renderComponent(Parent);
@ -178,28 +181,31 @@ describe('content projection', () => {
}); });
it('should project content with container into root', () => { it('should project content with container into root', () => {
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
projection(1, 0); projection(1, 0);
} }
}); });
const Parent = createComponent('parent', function(ctx: {value: any}, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: {value: any}) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ container(1); } { container(1); }
elementEnd(); elementEnd();
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (ctx.value) { {
if (embeddedViewStart(0)) { if (ctx.value) {
text(0, 'content'); let rf0 = embeddedViewStart(0);
if (rf0 & RenderFlags.Create) {
text(0, 'content');
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}, [Child]); }, [Child]);
const parent = renderComponent(Parent); const parent = renderComponent(Parent);
@ -215,16 +221,16 @@ describe('content projection', () => {
}); });
it('should project content with container and if-else.', () => { it('should project content with container and if-else.', () => {
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'div'); elementStart(1, 'div');
{ projection(2, 0); } { projection(2, 0); }
elementEnd(); elementEnd();
} }
}); });
const Parent = createComponent('parent', function(ctx: {value: any}, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: {value: any}) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
text(1, '('); text(1, '(');
@ -233,21 +239,24 @@ describe('content projection', () => {
} }
elementEnd(); elementEnd();
} }
containerRefreshStart(2); if (rf & RenderFlags.Update) {
{ containerRefreshStart(2);
if (ctx.value) { {
if (embeddedViewStart(0)) { if (ctx.value) {
text(0, 'content'); let rf0 = embeddedViewStart(0);
if (rf0 & RenderFlags.Create) {
text(0, 'content');
}
embeddedViewEnd();
} else {
if (embeddedViewStart(1)) {
text(0, 'else');
}
embeddedViewEnd();
} }
embeddedViewEnd();
} else {
if (embeddedViewStart(1)) {
text(0, 'else');
}
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}, [Child]); }, [Child]);
const parent = renderComponent(Parent); const parent = renderComponent(Parent);
@ -272,32 +281,35 @@ describe('content projection', () => {
* % } * % }
* </div> * </div>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'div'); elementStart(1, 'div');
{ container(2); } { container(2); }
elementEnd(); elementEnd();
} }
containerRefreshStart(2); if (rf & RenderFlags.Update) {
{ containerRefreshStart(2);
if (!ctx.skipContent) { {
if (embeddedViewStart(0)) { if (!ctx.skipContent) {
elementStart(0, 'span'); let rf0 = embeddedViewStart(0);
projection(1, 0); if (rf0 & RenderFlags.Create) {
elementEnd(); elementStart(0, 'span');
projection(1, 0);
elementEnd();
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}); });
/** /**
* <child>content</child> * <child>content</child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
childCmptInstance = loadDirective(0); childCmptInstance = loadDirective(0);
@ -326,30 +338,33 @@ describe('content projection', () => {
* % } * % }
* </div> * </div>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'div'); elementStart(1, 'div');
{ container(2); } { container(2); }
elementEnd(); elementEnd();
} }
containerRefreshStart(2); if (rf & RenderFlags.Update) {
{ containerRefreshStart(2);
if (!ctx.skipContent) { {
if (embeddedViewStart(0)) { if (!ctx.skipContent) {
projection(0, 0); let rf0 = embeddedViewStart(0);
if (rf0 & RenderFlags.Create) {
projection(0, 0);
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}); });
/** /**
* <child>content</child> * <child>content</child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
childCmptInstance = loadDirective(0); childCmptInstance = loadDirective(0);
@ -378,32 +393,35 @@ describe('content projection', () => {
* % } * % }
* </div> * </div>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'div'); elementStart(1, 'div');
{ container(2); } { container(2); }
elementEnd(); elementEnd();
} }
containerRefreshStart(2); if (rf & RenderFlags.Update) {
{ containerRefreshStart(2);
if (!ctx.skipContent) { {
if (embeddedViewStart(0)) { if (!ctx.skipContent) {
text(0, 'before-'); let rf0 = embeddedViewStart(0);
projection(1, 0); if (rf0 & RenderFlags.Create) {
text(2, '-after'); text(0, 'before-');
projection(1, 0);
text(2, '-after');
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}); });
/** /**
* <child>content</child> * <child>content</child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
childCmptInstance = loadDirective(0); childCmptInstance = loadDirective(0);
@ -426,8 +444,8 @@ describe('content projection', () => {
* <div><ng-content></ng-content></div> * <div><ng-content></ng-content></div>
* <span><ng-content></ng-content></span> * <span><ng-content></ng-content></span>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'div'); elementStart(1, 'div');
{ projection(2, 0); } { projection(2, 0); }
@ -441,8 +459,8 @@ describe('content projection', () => {
/** /**
* <child>content</child> * <child>content</child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ text(1, 'content'); } { text(1, 'content'); }
elementEnd(); elementEnd();
@ -472,31 +490,34 @@ describe('content projection', () => {
* % } * % }
* </div> * </div>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
projection(1, 0); projection(1, 0);
elementStart(2, 'div'); elementStart(2, 'div');
{ container(3); } { container(3); }
elementEnd(); elementEnd();
} }
containerRefreshStart(3); if (rf & RenderFlags.Update) {
{ containerRefreshStart(3);
if (ctx.show) { {
if (embeddedViewStart(0)) { if (ctx.show) {
projection(0, 0); let rf0 = embeddedViewStart(0);
if (rf0 & RenderFlags.Create) {
projection(0, 0);
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}); });
/** /**
* <child>content</child> * <child>content</child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
childCmptInstance = loadDirective(0); childCmptInstance = loadDirective(0);
@ -521,8 +542,8 @@ describe('content projection', () => {
* <div id="first"><ng-content select="span[title=toFirst]"></ng-content></div> * <div id="first"><ng-content select="span[title=toFirst]"></ng-content></div>
* <div id="second"><ng-content select="span[title=toSecond]"></ng-content></div> * <div id="second"><ng-content select="span[title=toSecond]"></ng-content></div>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef( projectionDef(
0, [[['span', 'title', 'toFirst']], [['span', 'title', 'toSecond']]], 0, [[['span', 'title', 'toFirst']], [['span', 'title', 'toSecond']]],
['span[title=toFirst]', 'span[title=toSecond]']); ['span[title=toFirst]', 'span[title=toSecond]']);
@ -541,8 +562,8 @@ describe('content projection', () => {
* <span title="toSecond">2</span> * <span title="toSecond">2</span>
* </child> * </child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
elementStart(1, 'span', ['title', 'toFirst']); elementStart(1, 'span', ['title', 'toFirst']);
@ -567,8 +588,8 @@ describe('content projection', () => {
* <div id="first"><ng-content select="span.toFirst"></ng-content></div> * <div id="first"><ng-content select="span.toFirst"></ng-content></div>
* <div id="second"><ng-content select="span.toSecond"></ng-content></div> * <div id="second"><ng-content select="span.toSecond"></ng-content></div>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef( projectionDef(
0, 0,
[ [
@ -591,8 +612,8 @@ describe('content projection', () => {
* <span class="toSecond">2</span> * <span class="toSecond">2</span>
* </child> * </child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
elementStart(1, 'span', ['class', 'toFirst']); elementStart(1, 'span', ['class', 'toFirst']);
@ -617,8 +638,8 @@ describe('content projection', () => {
* <div id="first"><ng-content select="span.toFirst"></ng-content></div> * <div id="first"><ng-content select="span.toFirst"></ng-content></div>
* <div id="second"><ng-content select="span.toSecond"></ng-content></div> * <div id="second"><ng-content select="span.toSecond"></ng-content></div>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef( projectionDef(
0, 0,
[ [
@ -641,8 +662,8 @@ describe('content projection', () => {
* <span class="toSecond noise">2</span> * <span class="toSecond noise">2</span>
* </child> * </child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
elementStart(1, 'span', ['class', 'other toFirst']); elementStart(1, 'span', ['class', 'other toFirst']);
@ -667,8 +688,8 @@ describe('content projection', () => {
* <div id="first"><ng-content select="span"></ng-content></div> * <div id="first"><ng-content select="span"></ng-content></div>
* <div id="second"><ng-content select="span.toSecond"></ng-content></div> * <div id="second"><ng-content select="span.toSecond"></ng-content></div>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef( projectionDef(
0, [[['span']], [['span', SelectorFlags.CLASS, 'toSecond']]], 0, [[['span']], [['span', SelectorFlags.CLASS, 'toSecond']]],
['span', 'span.toSecond']); ['span', 'span.toSecond']);
@ -687,8 +708,8 @@ describe('content projection', () => {
* <span class="toSecond">2</span> * <span class="toSecond">2</span>
* </child> * </child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
elementStart(1, 'span', ['class', 'toFirst']); elementStart(1, 'span', ['class', 'toFirst']);
@ -713,8 +734,8 @@ describe('content projection', () => {
* <div id="first"><ng-content select="span.toFirst"></ng-content></div> * <div id="first"><ng-content select="span.toFirst"></ng-content></div>
* <div id="second"><ng-content></ng-content></div> * <div id="second"><ng-content></ng-content></div>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0, [[['span', SelectorFlags.CLASS, 'toFirst']]], ['span.toFirst']); projectionDef(0, [[['span', SelectorFlags.CLASS, 'toFirst']]], ['span.toFirst']);
elementStart(1, 'div', ['id', 'first']); elementStart(1, 'div', ['id', 'first']);
{ projection(2, 0, 1); } { projection(2, 0, 1); }
@ -731,8 +752,8 @@ describe('content projection', () => {
* <span class="toSecond noise">2</span> * <span class="toSecond noise">2</span>
* </child> * </child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
elementStart(1, 'span', ['class', 'toFirst']); elementStart(1, 'span', ['class', 'toFirst']);
@ -758,8 +779,8 @@ describe('content projection', () => {
* <div id="first"><ng-content></ng-content></div> * <div id="first"><ng-content></ng-content></div>
* <div id="second"><ng-content select="span.toSecond"></ng-content></div> * <div id="second"><ng-content select="span.toSecond"></ng-content></div>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0, [[['span', SelectorFlags.CLASS, 'toSecond']]], ['span.toSecond']); projectionDef(0, [[['span', SelectorFlags.CLASS, 'toSecond']]], ['span.toSecond']);
elementStart(1, 'div', ['id', 'first']); elementStart(1, 'div', ['id', 'first']);
{ projection(2, 0); } { projection(2, 0); }
@ -777,8 +798,8 @@ describe('content projection', () => {
* remaining * remaining
* </child> * </child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
elementStart(1, 'span'); elementStart(1, 'span');
@ -810,8 +831,8 @@ describe('content projection', () => {
* <hr> * <hr>
* <ng-content></ng-content> * <ng-content></ng-content>
*/ */
const GrandChild = createComponent('grand-child', function(ctx: any, cm: boolean) { const GrandChild = createComponent('grand-child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0, [[['span']]], ['span']); projectionDef(0, [[['span']]], ['span']);
projection(1, 0, 1); projection(1, 0, 1);
elementStart(2, 'hr'); elementStart(2, 'hr');
@ -826,8 +847,8 @@ describe('content projection', () => {
* <span>in child template</span> * <span>in child template</span>
* </grand-child> * </grand-child>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'grand-child'); elementStart(1, 'grand-child');
{ {
@ -847,8 +868,8 @@ describe('content projection', () => {
* </div> * </div>
* </child> * </child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
elementStart(1, 'span'); elementStart(1, 'span');
@ -872,8 +893,8 @@ describe('content projection', () => {
* <hr> * <hr>
* <ng-content select="[card-content]"></ng-content> * <ng-content select="[card-content]"></ng-content>
*/ */
const Card = createComponent('card', function(ctx: any, cm: boolean) { const Card = createComponent('card', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef( projectionDef(
0, [[['', 'card-title', '']], [['', 'card-content', '']]], 0, [[['', 'card-title', '']], [['', 'card-content', '']]],
['[card-title]', '[card-content]']); ['[card-title]', '[card-content]']);
@ -890,8 +911,8 @@ describe('content projection', () => {
* <ng-content card-content></ng-content> * <ng-content card-content></ng-content>
* </card> * </card>
*/ */
const CardWithTitle = createComponent('card-with-title', function(ctx: any, cm: boolean) { const CardWithTitle = createComponent('card-with-title', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'card'); elementStart(1, 'card');
{ {
@ -909,8 +930,8 @@ describe('content projection', () => {
* content * content
* </card-with-title> * </card-with-title>
*/ */
const App = createComponent('app', function(ctx: any, cm: boolean) { const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'card-with-title'); elementStart(0, 'card-with-title');
{ text(1, 'content'); } { text(1, 'content'); }
elementEnd(); elementEnd();
@ -931,8 +952,8 @@ describe('content projection', () => {
* <hr> * <hr>
* <ng-content select="[card-content]"></ng-content> * <ng-content select="[card-content]"></ng-content>
*/ */
const Card = createComponent('card', function(ctx: any, cm: boolean) { const Card = createComponent('card', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef( projectionDef(
0, [[['', 'card-title', '']], [['', 'card-content', '']]], 0, [[['', 'card-title', '']], [['', 'card-content', '']]],
['[card-title]', '[card-content]']); ['[card-title]', '[card-content]']);
@ -949,8 +970,8 @@ describe('content projection', () => {
* <ng-content ngProjectAs="[card-content]"></ng-content> * <ng-content ngProjectAs="[card-content]"></ng-content>
* </card> * </card>
*/ */
const CardWithTitle = createComponent('card-with-title', function(ctx: any, cm: boolean) { const CardWithTitle = createComponent('card-with-title', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'card'); elementStart(1, 'card');
{ {
@ -968,8 +989,8 @@ describe('content projection', () => {
* content * content
* </card-with-title> * </card-with-title>
*/ */
const App = createComponent('app', function(ctx: any, cm: boolean) { const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'card-with-title'); elementStart(0, 'card-with-title');
{ text(1, 'content'); } { text(1, 'content'); }
elementEnd(); elementEnd();
@ -987,8 +1008,8 @@ describe('content projection', () => {
/** /**
* <ng-content select="div"></ng-content> * <ng-content select="div"></ng-content>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0, [[['div']]], ['div']); projectionDef(0, [[['div']]], ['div']);
projection(1, 0, 1); projection(1, 0, 1);
} }
@ -1000,8 +1021,8 @@ describe('content projection', () => {
* <div>should project</div> * <div>should project</div>
* </child> * </child>
*/ */
const Parent = createComponent('parent', function(ctx: any, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ {
elementStart(1, 'div', ['ngProjectAs', 'span']); elementStart(1, 'div', ['ngProjectAs', 'span']);
@ -1026,8 +1047,8 @@ describe('content projection', () => {
* <ng-content select="div"></ng-content> * <ng-content select="div"></ng-content>
* </span> * </span>
*/ */
const Child = createComponent('child', function(ctx: any, cm: boolean) { const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0, [[['div']]], ['div']); projectionDef(0, [[['div']]], ['div']);
elementStart(1, 'span'); elementStart(1, 'span');
{ projection(2, 0, 1); } { projection(2, 0, 1); }
@ -1040,24 +1061,27 @@ describe('content projection', () => {
* <div *ngIf="true">content</div> * <div *ngIf="true">content</div>
* </child> * </child>
*/ */
const Parent = createComponent('parent', function(ctx: {value: any}, cm: boolean) { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: {value: any}) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ container(1, undefined, 'div'); } { container(1, undefined, 'div'); }
elementEnd(); elementEnd();
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (true) { {
if (embeddedViewStart(0)) { if (true) {
elementStart(0, 'div'); let rf0 = embeddedViewStart(0);
{ text(1, 'content'); } if (rf0 & RenderFlags.Create) {
elementEnd(); elementStart(0, 'div');
{ text(1, 'content'); }
elementEnd();
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}, [Child]); }, [Child]);
const parent = renderComponent(Parent); const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('<child><span><div>content</div></span></child>'); expect(toHtml(parent)).toEqual('<child><span><div>content</div></span></child>');

View File

@ -8,32 +8,36 @@
import {defineComponent} from '../../src/render3/definition'; import {defineComponent} from '../../src/render3/definition';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, text, textBinding} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {ComponentFixture, createComponent, renderToHtml} from './render_util'; import {ComponentFixture, createComponent, renderToHtml} from './render_util';
describe('JS control flow', () => { describe('JS control flow', () => {
it('should work with if block', () => { it('should work with if block', () => {
const ctx: {message: string | null, condition: boolean} = {message: 'Hello', condition: true}; const ctx: {message: string | null, condition: boolean} = {message: 'Hello', condition: true};
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
{ container(1); } { container(1); }
elementEnd(); elementEnd();
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (ctx.condition) { {
let cm1 = embeddedViewStart(1); if (ctx.condition) {
{ let rf1 = embeddedViewStart(1);
if (cm1) { {
elementStart(0, 'span'); if (rf1 & RenderFlags.Create) {
{ text(1); } elementStart(0, 'span');
elementEnd(); { text(1); }
elementEnd();
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(ctx.message));
}
} }
textBinding(1, bind(ctx.message)); embeddedViewEnd();
} }
embeddedViewEnd();
} }
} }
containerRefreshEnd(); containerRefreshEnd();
@ -63,40 +67,44 @@ describe('JS control flow', () => {
* % } * % }
* </div> * </div>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
{ container(1); } { container(1); }
elementEnd(); elementEnd();
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (ctx.condition) { {
let cm1 = embeddedViewStart(1); if (ctx.condition) {
{ let rf1 = embeddedViewStart(1);
if (cm1) {
elementStart(0, 'span');
{ container(1); }
elementEnd();
}
containerRefreshStart(1);
{ {
if (ctx.condition2) { if (rf1 & RenderFlags.Create) {
let cm2 = embeddedViewStart(2); elementStart(0, 'span');
{ container(1); }
elementEnd();
}
if (rf1 & RenderFlags.Update) {
containerRefreshStart(1);
{ {
if (cm2) { if (ctx.condition2) {
text(0, 'Hello'); let rf2 = embeddedViewStart(2);
{
if (rf2 & RenderFlags.Create) {
text(0, 'Hello');
}
}
embeddedViewEnd();
} }
} }
embeddedViewEnd(); containerRefreshEnd();
} }
} }
containerRefreshEnd(); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
expect(renderToHtml(Template, ctx)).toEqual('<div><span>Hello</span></div>'); expect(renderToHtml(Template, ctx)).toEqual('<div><span>Hello</span></div>');
@ -139,33 +147,35 @@ describe('JS control flow', () => {
* 3 * 3
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
if (ctx.condition1) { containerRefreshStart(0);
const cm1 = embeddedViewStart(1); if (ctx.condition1) {
if (cm1) { const rf1 = embeddedViewStart(1);
text(0, '1'); if (rf1 & RenderFlags.Create) {
text(0, '1');
}
embeddedViewEnd();
} // can't have ; here due linting rules
if (ctx.condition2) {
const rf2 = embeddedViewStart(2);
if (rf2 & RenderFlags.Create) {
text(0, '2');
}
embeddedViewEnd();
} // can't have ; here due linting rules
if (ctx.condition3) {
const rf3 = embeddedViewStart(3);
if (rf3 & RenderFlags.Create) {
text(0, '3');
}
embeddedViewEnd();
} }
embeddedViewEnd(); containerRefreshEnd();
} // can't have ; here due linting rules
if (ctx.condition2) {
const cm2 = embeddedViewStart(2);
if (cm2) {
text(0, '2');
}
embeddedViewEnd();
} // can't have ; here due linting rules
if (ctx.condition3) {
const cm3 = embeddedViewStart(3);
if (cm3) {
text(0, '3');
}
embeddedViewEnd();
} }
containerRefreshEnd();
} }
expect(renderToHtml(Template, ctx)).toEqual('123'); expect(renderToHtml(Template, ctx)).toEqual('123');
@ -175,39 +185,43 @@ describe('JS control flow', () => {
}); });
it('should work with containers with views as parents', () => { it('should work with containers with views as parents', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
{ text(1, 'hello'); } { text(1, 'hello'); }
elementEnd(); elementEnd();
container(2); container(2);
} }
containerRefreshStart(2); if (rf & RenderFlags.Update) {
{ containerRefreshStart(2);
if (ctx.condition1) { {
let cm0 = embeddedViewStart(0); if (ctx.condition1) {
{ let rf0 = embeddedViewStart(0);
if (cm0) {
container(0);
}
containerRefreshStart(0);
{ {
if (ctx.condition2) { if (rf0 & RenderFlags.Create) {
let cm0 = embeddedViewStart(0); container(0);
}
if (rf0 & RenderFlags.Update) {
containerRefreshStart(0);
{ {
if (cm0) { if (ctx.condition2) {
text(0, 'world'); let rf0 = embeddedViewStart(0);
{
if (rf0 & RenderFlags.Create) {
text(0, 'world');
}
}
embeddedViewEnd();
} }
} }
embeddedViewEnd(); containerRefreshEnd();
} }
} }
containerRefreshEnd(); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
expect(renderToHtml(Template, {condition1: true, condition2: true})) expect(renderToHtml(Template, {condition1: true, condition2: true}))
@ -220,28 +234,32 @@ describe('JS control flow', () => {
it('should work with loop block', () => { it('should work with loop block', () => {
const ctx: {data: string[] | null} = {data: ['a', 'b', 'c']}; const ctx: {data: string[] | null} = {data: ['a', 'b', 'c']};
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'ul'); elementStart(0, 'ul');
{ container(1); } { container(1); }
elementEnd(); elementEnd();
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
for (let i = 0; i < ctx.data.length; i++) { {
let cm1 = embeddedViewStart(1); for (let i = 0; i < ctx.data.length; i++) {
{ let rf1 = embeddedViewStart(1);
if (cm1) { {
elementStart(0, 'li'); if (rf1 & RenderFlags.Create) {
{ text(1); } elementStart(0, 'li');
elementEnd(); { text(1); }
elementEnd();
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(ctx.data[i]));
}
} }
textBinding(1, bind(ctx.data[i])); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
expect(renderToHtml(Template, ctx)).toEqual('<ul><li>a</li><li>b</li><li>c</li></ul>'); expect(renderToHtml(Template, ctx)).toEqual('<ul><li>a</li><li>b</li><li>c</li></ul>');
@ -266,38 +284,45 @@ describe('JS control flow', () => {
it('should work with nested loop blocks', () => { it('should work with nested loop blocks', () => {
const ctx: {data: string[][] | null} = {data: [['a', 'b', 'c'], ['m', 'n']]}; const ctx: {data: string[][] | null} = {data: [['a', 'b', 'c'], ['m', 'n']]};
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'ul'); elementStart(0, 'ul');
{ container(1); } { container(1); }
elementEnd(); elementEnd();
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
for (let i = 0; i < ctx.data[0].length; i++) { {
let cm1 = embeddedViewStart(1); for (let i = 0; i < ctx.data[0].length; i++) {
{ let rf1 = embeddedViewStart(1);
if (cm1) {
elementStart(0, 'li');
{ container(1); }
elementEnd();
}
containerRefreshStart(1);
{ {
ctx.data[1].forEach((value: string, ind: number) => { if (rf1 & RenderFlags.Create) {
if (embeddedViewStart(2)) { elementStart(0, 'li');
text(0); { container(1); }
elementEnd();
}
if (rf1 & RenderFlags.Update) {
containerRefreshStart(1);
{
ctx.data[1].forEach((value: string, ind: number) => {
let rf2 = embeddedViewStart(2);
if (rf2 & RenderFlags.Create) {
text(0);
}
if (rf2 & RenderFlags.Update) {
textBinding(0, bind(ctx.data[0][i] + value));
}
embeddedViewEnd();
});
} }
textBinding(0, bind(ctx.data[0][i] + value)); containerRefreshEnd();
embeddedViewEnd(); }
});
} }
containerRefreshEnd(); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
expect(renderToHtml(Template, ctx)).toEqual('<ul><li>aman</li><li>bmbn</li><li>cmcn</li></ul>'); expect(renderToHtml(Template, ctx)).toEqual('<ul><li>aman</li><li>bmbn</li><li>cmcn</li></ul>');
@ -321,8 +346,8 @@ describe('JS control flow', () => {
* After * After
* <div> * <div>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
{ {
text(1, 'Before'); text(1, 'Before');
@ -331,35 +356,42 @@ describe('JS control flow', () => {
} }
elementEnd(); elementEnd();
} }
containerRefreshStart(2); if (rf & RenderFlags.Update) {
{ containerRefreshStart(2);
for (let i = 0; i < ctx.cafes.length; i++) { {
let cm1 = embeddedViewStart(1); for (let i = 0; i < ctx.cafes.length; i++) {
{ let rf1 = embeddedViewStart(1);
if (cm1) {
elementStart(0, 'h2');
{ text(1); }
elementEnd();
container(2);
text(3, '-');
}
textBinding(1, bind(ctx.cafes[i].name));
containerRefreshStart(2);
{ {
for (let j = 0; j < ctx.cafes[i].entrees.length; j++) { if (rf1 & RenderFlags.Create) {
if (embeddedViewStart(1)) { elementStart(0, 'h2');
text(0); { text(1); }
elementEnd();
container(2);
text(3, '-');
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(ctx.cafes[i].name));
containerRefreshStart(2);
{
for (let j = 0; j < ctx.cafes[i].entrees.length; j++) {
let rf2 = embeddedViewStart(2);
if (rf2 & RenderFlags.Create) {
text(0);
}
if (rf2 & RenderFlags.Update) {
textBinding(0, bind(ctx.cafes[i].entrees[j]));
}
embeddedViewEnd();
}
} }
textBinding(0, bind(ctx.cafes[i].entrees[j])); containerRefreshEnd();
embeddedViewEnd();
} }
} }
containerRefreshEnd(); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
const ctx = { const ctx = {
@ -401,8 +433,8 @@ describe('JS control flow', () => {
* After * After
* <div> * <div>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
{ {
text(1, 'Before'); text(1, 'Before');
@ -411,52 +443,61 @@ describe('JS control flow', () => {
} }
elementEnd(); elementEnd();
} }
containerRefreshStart(2); if (rf & RenderFlags.Update) {
{ containerRefreshStart(2);
for (let i = 0; i < ctx.cafes.length; i++) { {
let cm1 = embeddedViewStart(1); for (let i = 0; i < ctx.cafes.length; i++) {
{ let rf1 = embeddedViewStart(1);
if (cm1) {
elementStart(0, 'h2');
{ text(1); }
elementEnd();
container(2);
text(3, '-');
}
textBinding(1, bind(ctx.cafes[i].name));
containerRefreshStart(2);
{ {
for (let j = 0; j < ctx.cafes[i].entrees.length; j++) { if (rf1 & RenderFlags.Create) {
let cm1 = embeddedViewStart(1); elementStart(0, 'h2');
{ text(1); }
elementEnd();
container(2);
text(3, '-');
}
if (rf1 & RenderFlags.Update) {
textBinding(1, bind(ctx.cafes[i].name));
containerRefreshStart(2);
{ {
if (cm1) { for (let j = 0; j < ctx.cafes[i].entrees.length; j++) {
elementStart(0, 'h3'); let rf1 = embeddedViewStart(1);
{ text(1); } {
elementEnd(); if (rf1 & RenderFlags.Create) {
container(2); elementStart(0, 'h3');
} { text(1); }
textBinding(1, bind(ctx.cafes[i].entrees[j].name)); elementEnd();
containerRefreshStart(2); container(2);
{ }
for (let k = 0; k < ctx.cafes[i].entrees[j].foods.length; k++) { if (rf1 & RenderFlags.Update) {
if (embeddedViewStart(1)) { textBinding(1, bind(ctx.cafes[i].entrees[j].name));
text(0); containerRefreshStart(2);
{
for (let k = 0; k < ctx.cafes[i].entrees[j].foods.length; k++) {
let rf2 = embeddedViewStart(1);
if (rf2 & RenderFlags.Create) {
text(0);
}
if (rf2 & RenderFlags.Update) {
textBinding(0, bind(ctx.cafes[i].entrees[j].foods[k]));
}
embeddedViewEnd();
}
}
containerRefreshEnd();
} }
textBinding(0, bind(ctx.cafes[i].entrees[j].foods[k]));
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
embeddedViewEnd(); containerRefreshEnd();
} }
} }
containerRefreshEnd(); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
const ctx = { const ctx = {
@ -491,37 +532,39 @@ describe('JS control flow', () => {
it('should work with if/else blocks', () => { it('should work with if/else blocks', () => {
const ctx: {message: string | null, condition: boolean} = {message: 'Hello', condition: true}; const ctx: {message: string | null, condition: boolean} = {message: 'Hello', condition: true};
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
{ container(1); } { container(1); }
elementEnd(); elementEnd();
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (ctx.condition) { {
let cm1 = embeddedViewStart(1); if (ctx.condition) {
{ let rf1 = embeddedViewStart(1);
if (cm1) { {
elementStart(0, 'span'); if (rf1 & RenderFlags.Create) {
{ text(1, 'Hello'); } elementStart(0, 'span');
elementEnd(); { text(1, 'Hello'); }
elementEnd();
}
} }
} embeddedViewEnd();
embeddedViewEnd(); } else {
} else { let rf2 = embeddedViewStart(2);
let cm2 = embeddedViewStart(2); {
{ if (rf2) {
if (cm2) { elementStart(0, 'div');
elementStart(0, 'div'); { text(1, 'Goodbye'); }
{ text(1, 'Goodbye'); } elementEnd();
elementEnd(); }
} }
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
expect(renderToHtml(Template, ctx)).toEqual('<div><span>Hello</span></div>'); expect(renderToHtml(Template, ctx)).toEqual('<div><span>Hello</span></div>');
@ -546,7 +589,7 @@ describe('JS control flow', () => {
log.push('comp!'); log.push('comp!');
return new Comp(); return new Comp();
}, },
template: function(ctx: Comp, cm: boolean) {} template: function(rf: RenderFlags, ctx: Comp) {}
}); });
} }
@ -558,35 +601,39 @@ describe('JS control flow', () => {
type: App, type: App,
selectors: [['app']], selectors: [['app']],
factory: () => new App(), factory: () => new App(),
template: function(ctx: any, cm: boolean) { template: function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
elementEnd(); elementEnd();
container(1); container(1);
container(2); container(2);
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (ctx.condition) { {
if (embeddedViewStart(0)) { if (ctx.condition) {
elementStart(0, 'comp'); let rf1 = embeddedViewStart(0);
elementEnd(); if (rf1 & RenderFlags.Create) {
elementStart(0, 'comp');
elementEnd();
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
} containerRefreshEnd();
containerRefreshEnd(); containerRefreshStart(2);
containerRefreshStart(2); {
{ if (ctx.condition2) {
if (ctx.condition2) { let rf1 = embeddedViewStart(0);
if (embeddedViewStart(0)) { if (rf1 & RenderFlags.Create) {
elementStart(0, 'comp'); elementStart(0, 'comp');
elementEnd(); elementEnd();
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}, },
directives: () => [Comp] directives: () => [Comp]
}); });
@ -609,7 +656,7 @@ describe('JS control flow', () => {
log.push('comp!'); log.push('comp!');
return new Comp(); return new Comp();
}, },
template: function(ctx: Comp, cm: boolean) {} template: function(rf: RenderFlags, ctx: Comp) {}
}); });
} }
@ -621,35 +668,39 @@ describe('JS control flow', () => {
type: App, type: App,
selectors: [['app']], selectors: [['app']],
factory: () => new App(), factory: () => new App(),
template: function(ctx: any, cm: boolean) { template: function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
elementEnd(); elementEnd();
container(1); container(1);
container(2); container(2);
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (ctx.condition) { {
if (embeddedViewStart(0)) { if (ctx.condition) {
elementStart(0, 'comp'); let rf1 = embeddedViewStart(0);
elementEnd(); if (rf1 & RenderFlags.Create) {
elementStart(0, 'comp');
elementEnd();
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
} containerRefreshEnd();
containerRefreshEnd(); containerRefreshStart(2);
containerRefreshStart(2); {
{ if (ctx.condition2) {
if (ctx.condition2) { let rf1 = embeddedViewStart(0);
if (embeddedViewStart(0)) { if (rf1 & RenderFlags.Create) {
elementStart(0, 'comp'); elementStart(0, 'comp');
elementEnd(); elementEnd();
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}, },
directives: () => [Comp] directives: () => [Comp]
}); });
@ -678,30 +729,38 @@ describe('JS for loop', () => {
* % } * % }
* </div> * </div>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
{ container(1); } { container(1); }
elementEnd(); elementEnd();
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
for (let i = 0; i < ctx.data1.length; i++) { {
if (embeddedViewStart(1)) { for (let i = 0; i < ctx.data1.length; i++) {
text(0); let rf2 = embeddedViewStart(1);
if (rf2 & RenderFlags.Create) {
text(0);
}
if (rf2 & RenderFlags.Update) {
textBinding(0, bind(ctx.data1[i]));
}
embeddedViewEnd();
} }
textBinding(0, bind(ctx.data1[i])); for (let j = 0; j < ctx.data2.length; j++) {
embeddedViewEnd(); let rf2 = embeddedViewStart(1);
} if (rf2 & RenderFlags.Create) {
for (let j = 0; j < ctx.data2.length; j++) { text(0);
if (embeddedViewStart(2)) { }
text(0); if (rf2 & RenderFlags.Update) {
textBinding(0, bind(ctx.data2[j]));
}
embeddedViewEnd();
} }
textBinding(0, bind(ctx.data2[j]));
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
expect(renderToHtml(Template, ctx)).toEqual('<div>abc12</div>'); expect(renderToHtml(Template, ctx)).toEqual('<div>abc12</div>');
@ -721,18 +780,20 @@ describe('function calls', () => {
it('should work', () => { it('should work', () => {
const ctx: {data: string[]} = {data: ['foo', 'bar']}; const ctx: {data: string[]} = {data: ['foo', 'bar']};
function spanify(ctx: {message: string | null}, cm: boolean) { function spanify(rf: RenderFlags, ctx: {message: string | null}) {
const message = ctx.message; const message = ctx.message;
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
{ text(1); } { text(1); }
elementEnd(); elementEnd();
} }
textBinding(1, bind(message)); if (rf & RenderFlags.Update) {
textBinding(1, bind(message));
}
} }
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
{ {
text(1, 'Before'); text(1, 'Before');
@ -742,20 +803,22 @@ describe('function calls', () => {
} }
elementEnd(); elementEnd();
} }
containerRefreshStart(2); if (rf & RenderFlags.Update) {
{ containerRefreshStart(2);
let cm0 = embeddedViewStart(0); {
{ spanify({message: ctx.data[0]}, cm0); } let rf0 = embeddedViewStart(0);
embeddedViewEnd(); { spanify(rf0, {message: ctx.data[0]}); }
embeddedViewEnd();
}
containerRefreshEnd();
containerRefreshStart(3);
{
let rf0 = embeddedViewStart(0);
{ spanify(rf0, {message: ctx.data[1]}); }
embeddedViewEnd();
}
containerRefreshEnd();
} }
containerRefreshEnd();
containerRefreshStart(3);
{
let cm0 = embeddedViewStart(0);
{ spanify({message: ctx.data[1]}, cm0); }
embeddedViewEnd();
}
containerRefreshEnd();
} }
expect(renderToHtml(Template, ctx)) expect(renderToHtml(Template, ctx))

View File

@ -7,6 +7,7 @@
*/ */
import {ChangeDetectorRef, ElementRef, TemplateRef, ViewContainerRef} from '@angular/core'; import {ChangeDetectorRef, ElementRef, TemplateRef, ViewContainerRef} from '@angular/core';
import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
import {defineComponent} from '../../src/render3/definition'; import {defineComponent} from '../../src/render3/definition';
import {InjectFlags, bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di'; import {InjectFlags, bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di';
@ -33,14 +34,17 @@ describe('di', () => {
} }
/** <div dir #dir="dir"> {{ dir.value }} </div> */ /** <div dir #dir="dir"> {{ dir.value }} </div> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', ''], ['dir', 'dir']); elementStart(0, 'div', ['dir', ''], ['dir', 'dir']);
{ text(2); } { text(2); }
elementEnd(); elementEnd();
} }
const tmp = load(1) as any; let tmp: any;
textBinding(2, bind(tmp.value)); if (rf & RenderFlags.Update) {
tmp = load(1);
textBinding(2, bind(tmp.value));
}
} }
expect(renderToHtml(Template, {}, [Directive])).toEqual('<div dir="">Created</div>'); expect(renderToHtml(Template, {}, [Directive])).toEqual('<div dir="">Created</div>');
@ -91,8 +95,8 @@ describe('di', () => {
* <span dirB dirC #dir="dirC"> {{ dir.value }} </span> * <span dirB dirC #dir="dirC"> {{ dir.value }} </span>
* </div> * </div>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dirA', '']); elementStart(0, 'div', ['dirA', '']);
{ {
elementStart(1, 'span', ['dirB', '', 'dirC', ''], ['dir', 'dirC']); elementStart(1, 'span', ['dirB', '', 'dirC', ''], ['dir', 'dirC']);
@ -101,8 +105,11 @@ describe('di', () => {
} }
elementEnd(); elementEnd();
} }
const tmp = load(2) as any; let tmp: any;
textBinding(3, bind(tmp.value)); if (rf & RenderFlags.Update) {
tmp = load(2);
textBinding(3, bind(tmp.value));
}
} }
const defs = [DirA, DirB, DirC]; const defs = [DirA, DirB, DirC];
@ -326,8 +333,8 @@ describe('di', () => {
type: App, type: App,
factory: () => new App(), factory: () => new App(),
/** <div dirA dirB dirC></div> */ /** <div dirA dirB dirC></div> */
template: (ctx: any, cm: boolean) => { template: (rf: RenderFlags, ctx: any) => {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dirA', '', 'dirB', '', 'dirC', 'dirC']); elementStart(0, 'div', ['dirA', '', 'dirB', '', 'dirC', 'dirC']);
elementEnd(); elementEnd();
} }
@ -516,16 +523,20 @@ describe('di', () => {
* {{ dir.value }} - {{ dirSame.value }} * {{ dir.value }} - {{ dirSame.value }}
* </div> * </div>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dirSame', 'dirSame', 'dir', 'dir']); elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dirSame', 'dirSame', 'dir', 'dir']);
{ text(3); } { text(3); }
elementEnd(); elementEnd();
} }
const tmp1 = load(1) as any; let tmp1: any;
const tmp2 = load(2) as any; let tmp2: any;
textBinding(3, interpolation2('', tmp2.value, '-', tmp1.value, '')); if (rf & RenderFlags.Update) {
tmp1 = load(1);
tmp2 = load(2);
textBinding(3, interpolation2('', tmp2.value, '-', tmp1.value, ''));
}
} }
const defs = [Directive, DirectiveSameInstance]; const defs = [Directive, DirectiveSameInstance];
@ -568,15 +579,19 @@ describe('di', () => {
* {{ dir.value }} - {{ dirSame.value }} * {{ dir.value }} - {{ dirSame.value }}
* </ng-template> * </ng-template>
*/ */
function Template(ctx: any, cm: any) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0, function() { container(0, function() {
}, undefined, ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']); }, undefined, ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']);
text(3); text(3);
} }
const tmp1 = load(1) as any; let tmp1: any;
const tmp2 = load(2) as any; let tmp2: any;
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.value, '')); if (rf & RenderFlags.Update) {
tmp1 = load(1);
tmp2 = load(2);
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.value, ''));
}
} }
const defs = [Directive, DirectiveSameInstance]; const defs = [Directive, DirectiveSameInstance];
@ -619,16 +634,19 @@ describe('di', () => {
* {{ dir.value }} - {{ dirSame.value }} * {{ dir.value }} - {{ dirSame.value }}
* </div> * </div>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']); elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']);
{ text(3); } { text(3); }
elementEnd(); elementEnd();
} }
let tmp1: any;
const tmp1 = load(1) as any; let tmp2: any;
const tmp2 = load(2) as any; if (rf & RenderFlags.Update) {
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.value, '')); tmp1 = load(1);
tmp2 = load(2);
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.value, ''));
}
} }
const defs = [Directive, DirectiveSameInstance]; const defs = [Directive, DirectiveSameInstance];
@ -649,8 +667,8 @@ describe('di', () => {
type: MyComp, type: MyComp,
selectors: [['my-comp']], selectors: [['my-comp']],
factory: () => comp = new MyComp(injectChangeDetectorRef()), factory: () => comp = new MyComp(injectChangeDetectorRef()),
template: function(ctx: MyComp, cm: boolean) { template: function(rf: RenderFlags, ctx: MyComp) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
projection(1, 0); projection(1, 0);
} }
@ -708,14 +726,17 @@ describe('di', () => {
it('should inject current component ChangeDetectorRef into directives on components', () => { it('should inject current component ChangeDetectorRef into directives on components', () => {
/** <my-comp dir dirSameInstance #dir="dir"></my-comp> {{ dir.value }} */ /** <my-comp dir dirSameInstance #dir="dir"></my-comp> {{ dir.value }} */
const MyApp = createComponent('my-app', function(ctx: any, cm: boolean) { const MyApp = createComponent('my-app', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp', ['dir', '', 'dirSame', ''], ['dir', 'dir']); elementStart(0, 'my-comp', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
elementEnd(); elementEnd();
text(2); text(2);
} }
const tmp = load(1) as any; let tmp: any;
textBinding(2, bind(tmp.value)); if (rf & RenderFlags.Update) {
tmp = load(1);
textBinding(2, bind(tmp.value));
}
}, directives); }, directives);
const app = renderComponent(MyApp); const app = renderComponent(MyApp);
@ -737,14 +758,17 @@ describe('di', () => {
selectors: [['my-app']], selectors: [['my-app']],
factory: () => new MyApp(injectChangeDetectorRef()), factory: () => new MyApp(injectChangeDetectorRef()),
/** <div dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */ /** <div dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */
template: function(ctx: any, cm: boolean) { template: function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']); elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
{ text(2); } { text(2); }
elementEnd(); elementEnd();
} }
const tmp = load(1) as any; let tmp: any;
textBinding(2, bind(tmp.value)); if (rf & RenderFlags.Update) {
tmp = load(1);
textBinding(2, bind(tmp.value));
}
}, },
directives: directives directives: directives
}); });
@ -772,8 +796,8 @@ describe('di', () => {
* </my-comp> * </my-comp>
* {{ dir.value }} * {{ dir.value }}
*/ */
template: function(ctx: any, cm: boolean) { template: function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp'); elementStart(0, 'my-comp');
{ {
elementStart(1, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']); elementStart(1, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
@ -783,7 +807,9 @@ describe('di', () => {
text(3); text(3);
} }
const tmp = load(2) as any; const tmp = load(2) as any;
textBinding(3, bind(tmp.value)); if (rf & RenderFlags.Update) {
textBinding(3, bind(tmp.value));
}
}, },
directives: directives directives: directives
}); });
@ -813,24 +839,30 @@ describe('di', () => {
* <div dir dirSameInstance #dir="dir"> {{ dir.value }} </div> * <div dir dirSameInstance #dir="dir"> {{ dir.value }} </div>
* % } * % }
*/ */
template: function(ctx: MyApp, cm: boolean) { template: function(rf: RenderFlags, ctx: MyApp) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (ctx.showing) { {
if (embeddedViewStart(0)) { if (ctx.showing) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']); let rf1 = embeddedViewStart(0);
{ text(2); } if (rf1 & RenderFlags.Create) {
elementEnd(); elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
{ text(2); }
elementEnd();
}
let tmp: any;
if (rf1 & RenderFlags.Update) {
tmp = load(1);
textBinding(2, bind(tmp.value));
}
} }
const tmp = load(1) as any; embeddedViewEnd();
textBinding(2, bind(tmp.value));
} }
embeddedViewEnd(); containerRefreshEnd();
} }
containerRefreshEnd();
}, },
directives: directives directives: directives
}); });
@ -855,21 +887,26 @@ describe('di', () => {
selectors: [['my-app']], selectors: [['my-app']],
factory: () => new MyApp(injectChangeDetectorRef()), factory: () => new MyApp(injectChangeDetectorRef()),
/** <div *myIf="showing" dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */ /** <div *myIf="showing" dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */
template: function(ctx: MyApp, cm: boolean) { template: function(rf: RenderFlags, ctx: MyApp) {
if (cm) { if (rf & RenderFlags.Create) {
container(0, C1, undefined, ['myIf', 'showing']); container(0, C1, undefined, ['myIf', 'showing']);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
containerRefreshEnd(); containerRefreshStart(0);
containerRefreshEnd();
}
function C1(ctx1: any, cm1: boolean) { function C1(rf1: RenderFlags, ctx1: any) {
if (cm1) { if (rf1 & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']); elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
{ text(2); } { text(2); }
elementEnd(); elementEnd();
} }
const tmp = load(1) as any; let tmp: any;
textBinding(2, bind(tmp.value)); if (rf1 & RenderFlags.Update) {
tmp = load(1);
textBinding(2, bind(tmp.value));
}
} }
}, },
directives: directives directives: directives
@ -889,8 +926,8 @@ describe('di', () => {
let exist: string|undefined = 'wrong'; let exist: string|undefined = 'wrong';
let nonExist: string|undefined = 'wrong'; let nonExist: string|undefined = 'wrong';
const MyApp = createComponent('my-app', function(ctx: any, cm: boolean) { const MyApp = createComponent('my-app', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['exist', 'existValue', 'other', 'ignore']); elementStart(0, 'div', ['exist', 'existValue', 'other', 'ignore']);
exist = injectAttribute('exist'); exist = injectAttribute('exist');
nonExist = injectAttribute('nonExist'); nonExist = injectAttribute('nonExist');
@ -1025,27 +1062,34 @@ describe('di', () => {
* </span> * </span>
* </div> * </div>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['parentDir', '']); elementStart(0, 'div', ['parentDir', '']);
{ container(1); } { container(1); }
elementEnd(); elementEnd();
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (embeddedViewStart(0)) { {
elementStart( let rf1 = embeddedViewStart(0);
0, 'span', ['childDir', '', 'child2Dir', ''], if (rf1 & RenderFlags.Create) {
['child1', 'childDir', 'child2', 'child2Dir']); elementStart(
{ text(3); } 0, 'span', ['childDir', '', 'child2Dir', ''],
elementEnd(); ['child1', 'childDir', 'child2', 'child2Dir']);
{ text(3); }
elementEnd();
}
let tmp1: any;
let tmp2: any;
if (rf & RenderFlags.Update) {
tmp1 = load(1);
tmp2 = load(2);
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.value, ''));
}
embeddedViewEnd();
} }
const tmp1 = load(1) as any; containerRefreshEnd();
const tmp2 = load(2) as any;
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.value, ''));
embeddedViewEnd();
} }
containerRefreshEnd();
} }
const defs = [ChildDirective, Child2Directive, ParentDirective]; const defs = [ChildDirective, Child2Directive, ParentDirective];

View File

@ -8,7 +8,7 @@
import {defineDirective} from '../../src/render3/index'; import {defineDirective} from '../../src/render3/index';
import {bind, elementEnd, elementProperty, elementStart, loadDirective} from '../../src/render3/instructions'; import {bind, elementEnd, elementProperty, elementStart, loadDirective} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {renderToHtml} from './render_util'; import {renderToHtml} from './render_util';
describe('directive', () => { describe('directive', () => {
@ -31,8 +31,8 @@ describe('directive', () => {
}); });
} }
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span', ['dir', '']); elementStart(0, 'span', ['dir', '']);
elementEnd(); elementEnd();
} }

View File

@ -8,21 +8,24 @@
import {defineComponent, defineDirective} from '../../src/render3/index'; import {defineComponent, defineDirective} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementAttribute, elementClassNamed, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, text, textBinding} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, elementAttribute, elementClassNamed, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {ComponentFixture, createComponent, renderToHtml} from './render_util'; import {ComponentFixture, createComponent, renderToHtml} from './render_util';
describe('exports', () => { describe('exports', () => {
it('should support export of DOM element', () => { it('should support export of DOM element', () => {
/** <input value="one" #myInput> {{ myInput.value }} */ /** <input value="one" #myInput> {{ myInput.value }} */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'input', ['value', 'one'], ['myInput', '']); elementStart(0, 'input', ['value', 'one'], ['myInput', '']);
elementEnd(); elementEnd();
text(2); text(2);
} }
const tmp = load(1) as any; let tmp: any;
textBinding(2, tmp.value); if (rf & RenderFlags.Update) {
tmp = load(1);
textBinding(2, tmp.value);
}
} }
expect(renderToHtml(Template, {})).toEqual('<input value="one">one'); expect(renderToHtml(Template, {})).toEqual('<input value="one">one');
@ -31,14 +34,17 @@ describe('exports', () => {
it('should support basic export of component', () => { it('should support basic export of component', () => {
/** <comp #myComp></comp> {{ myComp.name }} */ /** <comp #myComp></comp> {{ myComp.name }} */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'comp', null, ['myComp', '']); elementStart(0, 'comp', null, ['myComp', '']);
elementEnd(); elementEnd();
text(2); text(2);
} }
const tmp = load(1) as any; let tmp: any;
textBinding(2, tmp.name); if (rf & RenderFlags.Update) {
tmp = load(1);
textBinding(2, tmp.name);
}
} }
class MyComponent { class MyComponent {
@ -83,15 +89,18 @@ describe('exports', () => {
const defs = [MyComponent, MyDir]; const defs = [MyComponent, MyDir];
/** <comp #myComp></comp> <div [myDir]="myComp"></div> */ /** <comp #myComp></comp> <div [myDir]="myComp"></div> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'comp', null, ['myComp', '']); elementStart(0, 'comp', null, ['myComp', '']);
elementEnd(); elementEnd();
elementStart(2, 'div', ['myDir', '']); elementStart(2, 'div', ['myDir', '']);
elementEnd(); elementEnd();
} }
const tmp = load(1) as any; let tmp: any;
elementProperty(2, 'myDir', bind(tmp)); if (rf & RenderFlags.Update) {
tmp = load(1);
elementProperty(2, 'myDir', bind(tmp));
}
} }
renderToHtml(Template, {}, defs); renderToHtml(Template, {}, defs);
@ -101,14 +110,17 @@ describe('exports', () => {
it('should work with directives with exportAs set', () => { it('should work with directives with exportAs set', () => {
/** <div someDir #myDir="someDir"></div> {{ myDir.name }} */ /** <div someDir #myDir="someDir"></div> {{ myDir.name }} */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['someDir', ''], ['myDir', 'someDir']); elementStart(0, 'div', ['someDir', ''], ['myDir', 'someDir']);
elementEnd(); elementEnd();
text(2); text(2);
} }
const tmp = load(1) as any; let tmp: any;
textBinding(2, tmp.name); if (rf & RenderFlags.Update) {
tmp = load(1);
textBinding(2, tmp.name);
}
} }
class SomeDir { class SomeDir {
@ -127,8 +139,8 @@ describe('exports', () => {
it('should throw if export name is not found', () => { it('should throw if export name is not found', () => {
/** <div #myDir="someDir"></div> */ /** <div #myDir="someDir"></div> */
const App = createComponent('app', function(ctx: any, cm: boolean) { const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', null, ['myDir', 'someDir']); elementStart(0, 'div', null, ['myDir', 'someDir']);
elementEnd(); elementEnd();
} }
@ -142,14 +154,16 @@ describe('exports', () => {
describe('forward refs', () => { describe('forward refs', () => {
it('should work with basic text bindings', () => { it('should work with basic text bindings', () => {
/** {{ myInput.value}} <input value="one" #myInput> */ /** {{ myInput.value}} <input value="one" #myInput> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
elementStart(1, 'input', ['value', 'one'], ['myInput', '']); elementStart(1, 'input', ['value', 'one'], ['myInput', '']);
elementEnd(); elementEnd();
} }
const tmp = load(2) as any; const tmp = load(2) as any;
textBinding(0, bind(tmp.value)); if (rf & RenderFlags.Update) {
textBinding(0, bind(tmp.value));
}
} }
expect(renderToHtml(Template, {})).toEqual('one<input value="one">'); expect(renderToHtml(Template, {})).toEqual('one<input value="one">');
@ -158,15 +172,17 @@ describe('exports', () => {
it('should work with element properties', () => { it('should work with element properties', () => {
/** <div [title]="myInput.value"</div> <input value="one" #myInput> */ /** <div [title]="myInput.value"</div> <input value="one" #myInput> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
elementEnd(); elementEnd();
elementStart(1, 'input', ['value', 'one'], ['myInput', '']); elementStart(1, 'input', ['value', 'one'], ['myInput', '']);
elementEnd(); elementEnd();
} }
const tmp = load(2) as any; const tmp = load(2) as any;
elementProperty(0, 'title', bind(tmp.value)); if (rf & RenderFlags.Update) {
elementProperty(0, 'title', bind(tmp.value));
}
} }
expect(renderToHtml(Template, {})).toEqual('<div title="one"></div><input value="one">'); expect(renderToHtml(Template, {})).toEqual('<div title="one"></div><input value="one">');
@ -174,15 +190,17 @@ describe('exports', () => {
it('should work with element attrs', () => { it('should work with element attrs', () => {
/** <div [attr.aria-label]="myInput.value"</div> <input value="one" #myInput> */ /** <div [attr.aria-label]="myInput.value"</div> <input value="one" #myInput> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
elementEnd(); elementEnd();
elementStart(1, 'input', ['value', 'one'], ['myInput', '']); elementStart(1, 'input', ['value', 'one'], ['myInput', '']);
elementEnd(); elementEnd();
} }
const tmp = load(2) as any; const tmp = load(2) as any;
elementAttribute(0, 'aria-label', bind(tmp.value)); if (rf & RenderFlags.Update) {
elementAttribute(0, 'aria-label', bind(tmp.value));
}
} }
expect(renderToHtml(Template, {})).toEqual('<div aria-label="one"></div><input value="one">'); expect(renderToHtml(Template, {})).toEqual('<div aria-label="one"></div><input value="one">');
@ -190,15 +208,17 @@ describe('exports', () => {
it('should work with element classes', () => { it('should work with element classes', () => {
/** <div [class.red]="myInput.checked"</div> <input type="checkbox" checked #myInput> */ /** <div [class.red]="myInput.checked"</div> <input type="checkbox" checked #myInput> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
elementEnd(); elementEnd();
elementStart(1, 'input', ['type', 'checkbox', 'checked', 'true'], ['myInput', '']); elementStart(1, 'input', ['type', 'checkbox', 'checked', 'true'], ['myInput', '']);
elementEnd(); elementEnd();
} }
const tmp = load(2) as any; const tmp = load(2) as any;
elementClassNamed(0, 'red', bind(tmp.checked)); if (rf & RenderFlags.Update) {
elementClassNamed(0, 'red', bind(tmp.checked));
}
} }
expect(renderToHtml(Template, {})) expect(renderToHtml(Template, {}))
@ -216,7 +236,7 @@ describe('exports', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: MyComponent, type: MyComponent,
selectors: [['comp']], selectors: [['comp']],
template: function(ctx: MyComponent, cm: boolean) {}, template: function(rf: RenderFlags, ctx: MyComponent) {},
factory: () => new MyComponent factory: () => new MyComponent
}); });
} }
@ -235,15 +255,18 @@ describe('exports', () => {
} }
/** <div [myDir]="myComp"></div><comp #myComp></comp> */ /** <div [myDir]="myComp"></div><comp #myComp></comp> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['myDir', '']); elementStart(0, 'div', ['myDir', '']);
elementEnd(); elementEnd();
elementStart(1, 'comp', null, ['myComp', '']); elementStart(1, 'comp', null, ['myComp', '']);
elementEnd(); elementEnd();
} }
const tmp = load(2) as any; let tmp: any;
elementProperty(0, 'myDir', bind(tmp)); if (rf & RenderFlags.Update) {
tmp = load(2) as any;
elementProperty(0, 'myDir', bind(tmp));
}
} }
renderToHtml(Template, {}, [MyComponent, MyDir]); renderToHtml(Template, {}, [MyComponent, MyDir]);
@ -253,8 +276,8 @@ describe('exports', () => {
it('should work with multiple forward refs', () => { it('should work with multiple forward refs', () => {
/** {{ myInput.value }} {{ myComp.name }} <comp #myComp></comp> <input value="one" #myInput> /** {{ myInput.value }} {{ myComp.name }} <comp #myComp></comp> <input value="one" #myInput>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
text(1); text(1);
elementStart(2, 'comp', null, ['myComp', '']); elementStart(2, 'comp', null, ['myComp', '']);
@ -262,10 +285,14 @@ describe('exports', () => {
elementStart(4, 'input', ['value', 'one'], ['myInput', '']); elementStart(4, 'input', ['value', 'one'], ['myInput', '']);
elementEnd(); elementEnd();
} }
const tmp1 = load(3) as any; let tmp1: any;
const tmp2 = load(5) as any; let tmp2: any;
textBinding(0, bind(tmp2.value)); if (rf & RenderFlags.Update) {
textBinding(1, bind(tmp1.name)); tmp1 = load(3) as any;
tmp2 = load(5) as any;
textBinding(0, bind(tmp2.value));
textBinding(1, bind(tmp1.name));
}
} }
let myComponent: MyComponent; let myComponent: MyComponent;
@ -287,29 +314,34 @@ describe('exports', () => {
}); });
it('should work inside a view container', () => { it('should work inside a view container', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
{ container(1); } { container(1); }
elementEnd(); elementEnd();
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (ctx.condition) { {
let cm1 = embeddedViewStart(1); if (ctx.condition) {
{ let rf1 = embeddedViewStart(1);
if (cm1) { {
text(0); let tmp: any;
elementStart(1, 'input', ['value', 'one'], ['myInput', '']); if (rf1 & RenderFlags.Create) {
elementEnd(); text(0);
elementStart(1, 'input', ['value', 'one'], ['myInput', '']);
elementEnd();
}
if (rf1 & RenderFlags.Update) {
tmp = load(2);
textBinding(0, bind(tmp.value));
}
} }
const tmp = load(2) as any; embeddedViewEnd();
textBinding(0, bind(tmp.value));
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
expect(renderToHtml(Template, { expect(renderToHtml(Template, {

View File

@ -6,8 +6,11 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {RenderFlags} from '@angular/core/src/render3';
import {defineComponent, defineDirective} from '../../src/render3/index'; import {defineComponent, defineDirective} from '../../src/render3/index';
import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, elementAttribute, elementClassNamed, elementEnd, elementProperty, elementStart, elementStyleNamed, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, load, loadDirective, projection, projectionDef, text, textBinding} from '../../src/render3/instructions'; import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, elementAttribute, elementClassNamed, elementEnd, elementProperty, elementStart, elementStyleNamed, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, load, loadDirective, projection, projectionDef, text, textBinding} from '../../src/render3/instructions';
import {LViewFlags} from '../../src/render3/interfaces/view';
import {ComponentFixture, containerEl, renderToHtml} from './render_util'; import {ComponentFixture, containerEl, renderToHtml} from './render_util';
@ -18,8 +21,8 @@ describe('render3 integration test', () => {
it('should render basic template', () => { it('should render basic template', () => {
expect(renderToHtml(Template, {})).toEqual('<span title="Hello">Greetings</span>'); expect(renderToHtml(Template, {})).toEqual('<span title="Hello">Greetings</span>');
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span', ['title', 'Hello']); elementStart(0, 'span', ['title', 'Hello']);
{ text(1, 'Greetings'); } { text(1, 'Greetings'); }
elementEnd(); elementEnd();
@ -31,24 +34,28 @@ describe('render3 integration test', () => {
expect(renderToHtml(Template, 'World')).toEqual('<h1>Hello, World!</h1>'); expect(renderToHtml(Template, 'World')).toEqual('<h1>Hello, World!</h1>');
expect(renderToHtml(Template, 'New World')).toEqual('<h1>Hello, New World!</h1>'); expect(renderToHtml(Template, 'New World')).toEqual('<h1>Hello, New World!</h1>');
function Template(name: string, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'h1'); elementStart(0, 'h1');
{ text(1); } { text(1); }
elementEnd(); elementEnd();
} }
textBinding(1, interpolation1('Hello, ', name, '!')); if (rf & RenderFlags.Update) {
textBinding(1, interpolation1('Hello, ', ctx, '!'));
}
} }
}); });
}); });
describe('text bindings', () => { describe('text bindings', () => {
it('should render "undefined" as "" when used with `bind()`', () => { it('should render "undefined" as "" when used with `bind()`', () => {
function Template(name: string, cm: boolean) { function Template(rf: RenderFlags, name: string) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, bind(name)); if (rf & RenderFlags.Update) {
textBinding(0, bind(name));
}
} }
expect(renderToHtml(Template, 'benoit')).toEqual('benoit'); expect(renderToHtml(Template, 'benoit')).toEqual('benoit');
@ -56,11 +63,13 @@ describe('render3 integration test', () => {
}); });
it('should render "null" as "" when used with `bind()`', () => { it('should render "null" as "" when used with `bind()`', () => {
function Template(name: string, cm: boolean) { function Template(rf: RenderFlags, name: string) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, bind(name)); if (rf & RenderFlags.Update) {
textBinding(0, bind(name));
}
} }
expect(renderToHtml(Template, 'benoit')).toEqual('benoit'); expect(renderToHtml(Template, 'benoit')).toEqual('benoit');
@ -68,11 +77,13 @@ describe('render3 integration test', () => {
}); });
it('should support creation-time values in text nodes', () => { it('should support creation-time values in text nodes', () => {
function Template(value: string, cm: boolean) { function Template(rf: RenderFlags, value: string) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, cm ? value : NO_CHANGE); if (rf & RenderFlags.Update) {
textBinding(0, rf & RenderFlags.Create ? value : NO_CHANGE);
}
} }
expect(renderToHtml(Template, 'once')).toEqual('once'); expect(renderToHtml(Template, 'once')).toEqual('once');
expect(renderToHtml(Template, 'twice')).toEqual('once'); expect(renderToHtml(Template, 'twice')).toEqual('once');
@ -82,21 +93,23 @@ describe('render3 integration test', () => {
describe('Siblings update', () => { describe('Siblings update', () => {
it('should handle a flat list of static/bound text nodes', () => { it('should handle a flat list of static/bound text nodes', () => {
function Template(name: string, cm: boolean) { function Template(rf: RenderFlags, name: string) {
if (cm) { if (rf & RenderFlags.Create) {
text(0, 'Hello '); text(0, 'Hello ');
text(1); text(1);
text(2, '!'); text(2, '!');
} }
textBinding(1, bind(name)); if (rf & RenderFlags.Update) {
textBinding(1, bind(name));
}
} }
expect(renderToHtml(Template, 'world')).toEqual('Hello world!'); expect(renderToHtml(Template, 'world')).toEqual('Hello world!');
expect(renderToHtml(Template, 'monde')).toEqual('Hello monde!'); expect(renderToHtml(Template, 'monde')).toEqual('Hello monde!');
}); });
it('should handle a list of static/bound text nodes as element children', () => { it('should handle a list of static/bound text nodes as element children', () => {
function Template(name: string, cm: boolean) { function Template(rf: RenderFlags, name: string) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'b'); elementStart(0, 'b');
{ {
text(1, 'Hello '); text(1, 'Hello ');
@ -105,15 +118,17 @@ describe('render3 integration test', () => {
} }
elementEnd(); elementEnd();
} }
textBinding(2, bind(name)); if (rf & RenderFlags.Update) {
textBinding(2, bind(name));
}
} }
expect(renderToHtml(Template, 'world')).toEqual('<b>Hello world!</b>'); expect(renderToHtml(Template, 'world')).toEqual('<b>Hello world!</b>');
expect(renderToHtml(Template, 'mundo')).toEqual('<b>Hello mundo!</b>'); expect(renderToHtml(Template, 'mundo')).toEqual('<b>Hello mundo!</b>');
}); });
it('should render/update text node as a child of a deep list of elements', () => { it('should render/update text node as a child of a deep list of elements', () => {
function Template(name: string, cm: boolean) { function Template(rf: RenderFlags, name: string) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'b'); elementStart(0, 'b');
{ {
elementStart(1, 'b'); elementStart(1, 'b');
@ -130,15 +145,17 @@ describe('render3 integration test', () => {
} }
elementEnd(); elementEnd();
} }
textBinding(4, interpolation1('Hello ', name, '!')); if (rf & RenderFlags.Update) {
textBinding(4, interpolation1('Hello ', name, '!'));
}
} }
expect(renderToHtml(Template, 'world')).toEqual('<b><b><b><b>Hello world!</b></b></b></b>'); 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>'); expect(renderToHtml(Template, 'mundo')).toEqual('<b><b><b><b>Hello mundo!</b></b></b></b>');
}); });
it('should update 2 sibling elements', () => { it('should update 2 sibling elements', () => {
function Template(id: any, cm: boolean) { function Template(rf: RenderFlags, id: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'b'); elementStart(0, 'b');
{ {
elementStart(1, 'span'); elementStart(1, 'span');
@ -149,7 +166,9 @@ describe('render3 integration test', () => {
} }
elementEnd(); elementEnd();
} }
elementAttribute(2, 'id', bind(id)); if (rf & RenderFlags.Update) {
elementAttribute(2, 'id', bind(id));
}
} }
expect(renderToHtml(Template, 'foo')) expect(renderToHtml(Template, 'foo'))
.toEqual('<b><span></span><span class="foo" id="foo"></span></b>'); .toEqual('<b><span></span><span class="foo" id="foo"></span></b>');
@ -158,8 +177,8 @@ describe('render3 integration test', () => {
}); });
it('should handle sibling text node after element with child text node', () => { it('should handle sibling text node after element with child text node', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'p'); elementStart(0, 'p');
{ text(1, 'hello'); } { text(1, 'hello'); }
elementEnd(); elementEnd();
@ -179,8 +198,8 @@ describe('render3 integration test', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: TodoComponent, type: TodoComponent,
selectors: [['todo']], selectors: [['todo']],
template: function TodoTemplate(ctx: any, cm: boolean) { template: function TodoTemplate(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'p'); elementStart(0, 'p');
{ {
text(1, 'Todo'); text(1, 'Todo');
@ -188,7 +207,9 @@ describe('render3 integration test', () => {
} }
elementEnd(); elementEnd();
} }
textBinding(2, bind(ctx.value)); if (rf & RenderFlags.Update) {
textBinding(2, bind(ctx.value));
}
}, },
factory: () => new TodoComponent factory: () => new TodoComponent
}); });
@ -197,8 +218,8 @@ describe('render3 integration test', () => {
const defs = [TodoComponent]; const defs = [TodoComponent];
it('should support a basic component template', () => { it('should support a basic component template', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'todo'); elementStart(0, 'todo');
elementEnd(); elementEnd();
} }
@ -208,8 +229,8 @@ describe('render3 integration test', () => {
}); });
it('should support a component template with sibling', () => { it('should support a component template with sibling', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'todo'); elementStart(0, 'todo');
elementEnd(); elementEnd();
text(1, 'two'); text(1, 'two');
@ -223,8 +244,8 @@ describe('render3 integration test', () => {
* <todo></todo> * <todo></todo>
* <todo></todo> * <todo></todo>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'todo'); elementStart(0, 'todo');
elementEnd(); elementEnd();
elementStart(1, 'todo'); elementStart(1, 'todo');
@ -244,11 +265,13 @@ describe('render3 integration test', () => {
type: TodoComponentHostBinding, type: TodoComponentHostBinding,
selectors: [['todo']], selectors: [['todo']],
template: function TodoComponentHostBindingTemplate( template: function TodoComponentHostBindingTemplate(
ctx: TodoComponentHostBinding, cm: boolean) { rf: RenderFlags, ctx: TodoComponentHostBinding) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, bind(ctx.title)); if (rf & RenderFlags.Update) {
textBinding(0, bind(ctx.title));
}
}, },
factory: () => cmptInstance = new TodoComponentHostBinding, factory: () => cmptInstance = new TodoComponentHostBinding,
hostBindings: function(directiveIndex: number, elementIndex: number): void { hostBindings: function(directiveIndex: number, elementIndex: number): void {
@ -260,8 +283,8 @@ describe('render3 integration test', () => {
}); });
} }
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'todo'); elementStart(0, 'todo');
elementEnd(); elementEnd();
} }
@ -279,7 +302,7 @@ describe('render3 integration test', () => {
type: HostAttributeComp, type: HostAttributeComp,
selectors: [['host-attr-comp']], selectors: [['host-attr-comp']],
factory: () => new HostAttributeComp(), factory: () => new HostAttributeComp(),
template: (ctx: HostAttributeComp, cm: boolean) => {}, template: (rf: RenderFlags, ctx: HostAttributeComp) => {},
attributes: ['role', 'button'] attributes: ['role', 'button']
}); });
} }
@ -295,20 +318,22 @@ describe('render3 integration test', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: MyComp, type: MyComp,
selectors: [['comp']], selectors: [['comp']],
template: function MyCompTemplate(ctx: any, cm: boolean) { template: function MyCompTemplate(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'p'); elementStart(0, 'p');
{ text(1); } { text(1); }
elementEnd(); elementEnd();
} }
textBinding(1, bind(ctx.name)); if (rf & RenderFlags.Update) {
textBinding(1, bind(ctx.name));
}
}, },
factory: () => new MyComp factory: () => new MyComp
}); });
} }
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'comp'); elementStart(0, 'comp');
elementEnd(); elementEnd();
} }
@ -328,22 +353,25 @@ describe('render3 integration test', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: MyComp, type: MyComp,
selectors: [['comp']], selectors: [['comp']],
template: function MyCompTemplate(ctx: any, cm: boolean) { template: function MyCompTemplate(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (ctx.condition) { {
if (embeddedViewStart(0)) { if (ctx.condition) {
elementStart(0, 'div'); let rf1 = embeddedViewStart(0);
{ text(1, 'text'); } if (rf1 & RenderFlags.Create) {
elementEnd(); elementStart(0, 'div');
{ text(1, 'text'); }
elementEnd();
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}, },
factory: () => new MyComp, factory: () => new MyComp,
inputs: {condition: 'condition'} inputs: {condition: 'condition'}
@ -351,12 +379,14 @@ describe('render3 integration test', () => {
} }
/** <comp [condition]="condition"></comp> */ /** <comp [condition]="condition"></comp> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'comp'); elementStart(0, 'comp');
elementEnd(); elementEnd();
} }
elementProperty(0, 'condition', bind(ctx.condition)); if (rf & RenderFlags.Update) {
elementProperty(0, 'condition', bind(ctx.condition));
}
} }
const defs = [MyComp]; const defs = [MyComp];
@ -381,49 +411,54 @@ describe('render3 integration test', () => {
afterTree: Tree; afterTree: Tree;
} }
function showLabel(ctx: {label: string | undefined}, cm: boolean) { function showLabel(rf: RenderFlags, ctx: {label: string | undefined}) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (ctx.label != null) { {
if (embeddedViewStart(0)) { if (ctx.label != null) {
text(0); let rf1 = embeddedViewStart(0);
if (rf1 & RenderFlags.Create) {
text(0);
}
if (rf1 & RenderFlags.Update) {
textBinding(0, bind(ctx.label));
}
embeddedViewEnd();
} }
textBinding(0, bind(ctx.label));
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
function showTree(ctx: {tree: Tree}, cm: boolean) { function showTree(rf: RenderFlags, ctx: {tree: Tree}) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
container(1); container(1);
container(2); container(2);
} }
containerRefreshStart(0); containerRefreshStart(0);
{ {
const cm0 = embeddedViewStart(0); const rf0 = embeddedViewStart(0);
{ showLabel({label: ctx.tree.beforeLabel}, cm0); } { showLabel(rf0, {label: ctx.tree.beforeLabel}); }
embeddedViewEnd(); embeddedViewEnd();
} }
containerRefreshEnd(); containerRefreshEnd();
containerRefreshStart(1); containerRefreshStart(1);
{ {
for (let subTree of ctx.tree.subTrees || []) { for (let subTree of ctx.tree.subTrees || []) {
const cm0 = embeddedViewStart(0); const rf0 = embeddedViewStart(0);
{ showTree({tree: subTree}, cm0); } { showTree(rf0, {tree: subTree}); }
embeddedViewEnd(); embeddedViewEnd();
} }
} }
containerRefreshEnd(); containerRefreshEnd();
containerRefreshStart(2); containerRefreshStart(2);
{ {
const cm0 = embeddedViewStart(0); const rf0 = embeddedViewStart(0);
{ showLabel({label: ctx.tree.afterLabel}, cm0); } { showLabel(rf0, {label: ctx.tree.afterLabel}); }
embeddedViewEnd(); embeddedViewEnd();
} }
containerRefreshEnd(); containerRefreshEnd();
@ -436,8 +471,8 @@ describe('render3 integration test', () => {
selectors: [['child']], selectors: [['child']],
type: ChildComponent, type: ChildComponent,
template: function ChildComponentTemplate( template: function ChildComponentTemplate(
ctx: {beforeTree: Tree, afterTree: Tree}, cm: boolean) { rf: RenderFlags, ctx: {beforeTree: Tree, afterTree: Tree}) {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
container(1); container(1);
projection(2, 0); projection(2, 0);
@ -445,15 +480,15 @@ describe('render3 integration test', () => {
} }
containerRefreshStart(1); containerRefreshStart(1);
{ {
const cm0 = embeddedViewStart(0); const rf0 = embeddedViewStart(0);
{ showTree({tree: ctx.beforeTree}, cm0); } { showTree(rf0, {tree: ctx.beforeTree}); }
embeddedViewEnd(); embeddedViewEnd();
} }
containerRefreshEnd(); containerRefreshEnd();
containerRefreshStart(3); containerRefreshStart(3);
{ {
const cm0 = embeddedViewStart(0); const rf0 = embeddedViewStart(0);
{ showTree({tree: ctx.afterTree}, cm0); } { showTree(rf0, {tree: ctx.afterTree}); }
embeddedViewEnd(); embeddedViewEnd();
} }
containerRefreshEnd(); containerRefreshEnd();
@ -463,21 +498,23 @@ describe('render3 integration test', () => {
}); });
} }
function parentTemplate(ctx: ParentCtx, cm: boolean) { function parentTemplate(rf: RenderFlags, ctx: ParentCtx) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'child'); elementStart(0, 'child');
{ container(1); } { container(1); }
elementEnd(); elementEnd();
} }
elementProperty(0, 'beforeTree', bind(ctx.beforeTree)); if (rf & RenderFlags.Update) {
elementProperty(0, 'afterTree', bind(ctx.afterTree)); elementProperty(0, 'beforeTree', bind(ctx.beforeTree));
containerRefreshStart(1); elementProperty(0, 'afterTree', bind(ctx.afterTree));
{ containerRefreshStart(1);
const cm0 = embeddedViewStart(0); {
{ showTree({tree: ctx.projectedTree}, cm0); } const rf0 = embeddedViewStart(0);
embeddedViewEnd(); { showTree(rf0, {tree: ctx.projectedTree}); }
embeddedViewEnd();
}
containerRefreshEnd();
} }
containerRefreshEnd();
} }
it('should work with a tree', () => { it('should work with a tree', () => {
@ -509,12 +546,14 @@ describe('render3 integration test', () => {
it('should support attribute bindings', () => { it('should support attribute bindings', () => {
const ctx: {title: string | null} = {title: 'Hello'}; const ctx: {title: string | null} = {title: 'Hello'};
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
elementEnd(); elementEnd();
} }
elementAttribute(0, 'title', bind(ctx.title)); if (rf & RenderFlags.Update) {
elementAttribute(0, 'title', bind(ctx.title));
}
} }
// initial binding // initial binding
@ -532,12 +571,14 @@ describe('render3 integration test', () => {
it('should stringify values used attribute bindings', () => { it('should stringify values used attribute bindings', () => {
const ctx: {title: any} = {title: NaN}; const ctx: {title: any} = {title: NaN};
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
elementEnd(); elementEnd();
} }
elementAttribute(0, 'title', bind(ctx.title)); if (rf & RenderFlags.Update) {
elementAttribute(0, 'title', bind(ctx.title));
}
} }
expect(renderToHtml(Template, ctx)).toEqual('<span title="NaN"></span>'); expect(renderToHtml(Template, ctx)).toEqual('<span title="NaN"></span>');
@ -547,33 +588,35 @@ describe('render3 integration test', () => {
}); });
it('should update bindings', () => { it('should update bindings', () => {
function Template(c: any, cm: boolean) { function Template(rf: RenderFlags, c: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'b'); elementStart(0, 'b');
elementEnd(); elementEnd();
} }
elementAttribute(0, 'a', interpolationV(c)); if (rf & RenderFlags.Update) {
elementAttribute(0, 'a0', bind(c[1])); elementAttribute(0, 'a', interpolationV(c));
elementAttribute(0, 'a1', interpolation1(c[0], c[1], c[16])); elementAttribute(0, 'a0', bind(c[1]));
elementAttribute(0, 'a2', interpolation2(c[0], c[1], c[2], c[3], c[16])); elementAttribute(0, 'a1', interpolation1(c[0], c[1], c[16]));
elementAttribute(0, 'a3', interpolation3(c[0], c[1], c[2], c[3], c[4], c[5], c[16])); elementAttribute(0, 'a2', interpolation2(c[0], c[1], c[2], c[3], c[16]));
elementAttribute( elementAttribute(0, 'a3', interpolation3(c[0], c[1], c[2], c[3], c[4], c[5], c[16]));
0, 'a4', interpolation4(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[16])); elementAttribute(
elementAttribute( 0, 'a4', interpolation4(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[16]));
0, 'a5', elementAttribute(
interpolation5(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[16])); 0, 'a5',
elementAttribute( interpolation5(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[16]));
0, 'a6', elementAttribute(
interpolation6( 0, 'a6', interpolation6(
c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11], c[16])); c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10],
elementAttribute( c[11], c[16]));
0, 'a7', interpolation7( elementAttribute(
c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11], 0, 'a7', interpolation7(
c[12], c[13], c[16])); c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10],
elementAttribute( c[11], c[12], c[13], c[16]));
0, 'a8', interpolation8( elementAttribute(
c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11], 0, 'a8', interpolation8(
c[12], c[13], c[14], c[15], c[16])); c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10],
c[11], c[12], c[13], c[14], c[15], c[16]));
}
} }
let args = ['(', 0, 'a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 6, 'g', 7, ')']; 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))
@ -592,29 +635,31 @@ describe('render3 integration test', () => {
it('should not update DOM if context has not changed', () => { it('should not update DOM if context has not changed', () => {
const ctx: {title: string | null} = {title: 'Hello'}; const ctx: {title: string | null} = {title: 'Hello'};
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
container(1); container(1);
elementEnd(); elementEnd();
} }
elementAttribute(0, 'title', bind(ctx.title)); if (rf & RenderFlags.Update) {
containerRefreshStart(1); elementAttribute(0, 'title', bind(ctx.title));
{ containerRefreshStart(1);
if (true) { {
let cm1 = embeddedViewStart(1); if (true) {
{ let rf1 = embeddedViewStart(1);
if (cm1) { {
elementStart(0, 'b'); if (rf1 & RenderFlags.Create) {
{} elementStart(0, 'b');
elementEnd(); {}
elementEnd();
}
elementAttribute(0, 'title', bind(ctx.title));
} }
elementAttribute(0, 'title', bind(ctx.title)); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
// initial binding // initial binding
@ -650,8 +695,8 @@ describe('render3 integration test', () => {
}); });
} }
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['hostBindingDir', '']); elementStart(0, 'div', ['hostBindingDir', '']);
elementEnd(); elementEnd();
} }
@ -670,12 +715,14 @@ describe('render3 integration test', () => {
describe('elementStyle', () => { describe('elementStyle', () => {
it('should support binding to styles', () => { it('should support binding to styles', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
elementEnd(); elementEnd();
} }
elementStyleNamed(0, 'border-color', bind(ctx)); if (rf & RenderFlags.Update) {
elementStyleNamed(0, 'border-color', bind(ctx));
}
} }
expect(renderToHtml(Template, 'red')).toEqual('<span style="border-color: red;"></span>'); expect(renderToHtml(Template, 'red')).toEqual('<span style="border-color: red;"></span>');
@ -685,12 +732,14 @@ describe('render3 integration test', () => {
}); });
it('should support binding to styles with suffix', () => { it('should support binding to styles with suffix', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
elementEnd(); elementEnd();
} }
elementStyleNamed(0, 'font-size', bind(ctx), 'px'); if (rf & RenderFlags.Update) {
elementStyleNamed(0, 'font-size', bind(ctx), 'px');
}
} }
expect(renderToHtml(Template, '100')).toEqual('<span style="font-size: 100px;"></span>'); expect(renderToHtml(Template, '100')).toEqual('<span style="font-size: 100px;"></span>');
@ -702,12 +751,14 @@ describe('render3 integration test', () => {
describe('elementClass', () => { describe('elementClass', () => {
it('should support CSS class toggle', () => { it('should support CSS class toggle', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
elementEnd(); elementEnd();
} }
elementClassNamed(0, 'active', bind(ctx)); if (rf & RenderFlags.Update) {
elementClassNamed(0, 'active', bind(ctx));
}
} }
expect(renderToHtml(Template, true)).toEqual('<span class="active"></span>'); expect(renderToHtml(Template, true)).toEqual('<span class="active"></span>');
@ -723,12 +774,14 @@ describe('render3 integration test', () => {
}); });
it('should work correctly with existing static classes', () => { it('should work correctly with existing static classes', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span', ['class', 'existing']); elementStart(0, 'span', ['class', 'existing']);
elementEnd(); elementEnd();
} }
elementClassNamed(0, 'active', bind(ctx)); if (rf & RenderFlags.Update) {
elementClassNamed(0, 'active', bind(ctx));
}
} }
expect(renderToHtml(Template, true)).toEqual('<span class="existing active"></span>'); expect(renderToHtml(Template, true)).toEqual('<span class="existing active"></span>');
@ -745,22 +798,24 @@ describe('render3 integration test', () => {
* <div></div> * <div></div>
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (ctx.condition) { {
if (embeddedViewStart(0)) { if (ctx.condition) {
elementStart(0, 'div'); let rf1 = embeddedViewStart(0);
{} if (rf1 & RenderFlags.Create) {
elementEnd(); elementStart(0, 'div');
elementEnd();
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
expect((Template as any).ngPrivateData).toBeUndefined(); expect((Template as any).ngPrivateData).toBeUndefined();

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
import {defineComponent, defineDirective} from '../../src/render3/index'; import {defineComponent, defineDirective} from '../../src/render3/index';
import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, listener, text} from '../../src/render3/instructions'; import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, listener, text} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {getRendererFactory2} from './imported_renderer2'; import {getRendererFactory2} from './imported_renderer2';
import {containerEl, renderComponent, renderToHtml} from './render_util'; import {containerEl, renderComponent, renderToHtml} from './render_util';
@ -26,8 +26,8 @@ describe('event listeners', () => {
type: MyComp, type: MyComp,
selectors: [['comp']], selectors: [['comp']],
/** <button (click)="onClick()"> Click me </button> */ /** <button (click)="onClick()"> Click me </button> */
template: function CompTemplate(ctx: any, cm: boolean) { template: function CompTemplate(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button'); elementStart(0, 'button');
{ {
listener('click', function() { return ctx.onClick(); }); listener('click', function() { return ctx.onClick(); });
@ -64,8 +64,8 @@ describe('event listeners', () => {
selectors: [['prevent-default-comp']], selectors: [['prevent-default-comp']],
factory: () => new PreventDefaultComp(), factory: () => new PreventDefaultComp(),
/** <button (click)="onClick($event)">Click</button> */ /** <button (click)="onClick($event)">Click</button> */
template: (ctx: PreventDefaultComp, cm: boolean) => { template: (rf: RenderFlags, ctx: PreventDefaultComp) => {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button'); elementStart(0, 'button');
{ {
listener('click', function($event: any) { return ctx.onClick($event); }); listener('click', function($event: any) { return ctx.onClick($event); });
@ -124,8 +124,8 @@ describe('event listeners', () => {
it('should call function chain on event emit', () => { it('should call function chain on event emit', () => {
/** <button (click)="onClick(); onClick2(); "> Click me </button> */ /** <button (click)="onClick(); onClick2(); "> Click me </button> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button'); elementStart(0, 'button');
{ {
listener('click', function() { listener('click', function() {
@ -159,8 +159,8 @@ describe('event listeners', () => {
it('should evaluate expression on event emit', () => { it('should evaluate expression on event emit', () => {
/** <button (click)="showing=!showing"> Click me </button> */ /** <button (click)="showing=!showing"> Click me </button> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button'); elementStart(0, 'button');
{ {
listener('click', function() { return ctx.showing = !ctx.showing; }); listener('click', function() { return ctx.showing = !ctx.showing; });
@ -188,25 +188,27 @@ describe('event listeners', () => {
* <button (click)="onClick()"> Click me </button> * <button (click)="onClick()"> Click me </button>
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (ctx.showing) { {
if (embeddedViewStart(1)) { if (ctx.showing) {
elementStart(0, 'button'); if (embeddedViewStart(1)) {
{ elementStart(0, 'button');
listener('click', function() { return ctx.onClick(); }); {
text(1, 'Click me'); listener('click', function() { return ctx.onClick(); });
text(1, 'Click me');
}
elementEnd();
} }
elementEnd(); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
let comp = new MyComp(); let comp = new MyComp();
@ -244,8 +246,8 @@ describe('event listeners', () => {
}); });
} }
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button', ['hostListenerDir', '']); elementStart(0, 'button', ['hostListenerDir', '']);
text(1, 'Click'); text(1, 'Click');
elementEnd(); elementEnd();
@ -271,36 +273,42 @@ describe('event listeners', () => {
* % } * % }
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (ctx.showing) { {
if (embeddedViewStart(0)) { if (ctx.showing) {
text(0, 'Hello'); let rf1 = embeddedViewStart(0);
container(1); if (rf1 & RenderFlags.Create) {
} text(0, 'Hello');
containerRefreshStart(1); container(1);
{
if (ctx.button) {
if (embeddedViewStart(0)) {
elementStart(0, 'button');
{
listener('click', function() { return ctx.onClick(); });
text(1, 'Click');
}
elementEnd();
}
embeddedViewEnd();
} }
if (rf1 & RenderFlags.Update) {
containerRefreshStart(1);
{
if (ctx.button) {
let rf1 = embeddedViewStart(0);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'button');
{
listener('click', function() { return ctx.onClick(); });
text(1, 'Click');
}
elementEnd();
}
embeddedViewEnd();
}
}
containerRefreshEnd();
}
embeddedViewEnd();
} }
containerRefreshEnd();
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
const comp = {showing: true, counter: 0, button: true, onClick: function() { this.counter++; }}; const comp = {showing: true, counter: 0, button: true, onClick: function() { this.counter++; }};
@ -329,24 +337,27 @@ describe('event listeners', () => {
* comp: * comp:
* <button (click)="onClick()"> Click </button> * <button (click)="onClick()"> Click </button>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (ctx.showing) { {
if (embeddedViewStart(0)) { if (ctx.showing) {
text(0, 'Hello'); let rf1 = embeddedViewStart(0);
elementStart(1, 'comp'); if (rf1 & RenderFlags.Create) {
elementEnd(); text(0, 'Hello');
elementStart(2, 'comp'); elementStart(1, 'comp');
elementEnd(); elementEnd();
elementStart(2, 'comp');
elementEnd();
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
const ctx = {showing: true}; const ctx = {showing: true};
@ -381,52 +392,59 @@ describe('event listeners', () => {
* % } * % }
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (ctx.condition) { {
if (embeddedViewStart(0)) { if (ctx.condition) {
text(0, 'Hello'); let rf1 = embeddedViewStart(0);
container(1); if (rf1 & RenderFlags.Create) {
container(2); text(0, 'Hello');
} container(1);
containerRefreshStart(1); container(2);
{
if (ctx.sub1) {
if (embeddedViewStart(0)) {
elementStart(0, 'button');
{
listener('click', function() { return ctx.counter1++; });
text(1, 'Click');
}
elementEnd();
}
embeddedViewEnd();
} }
} if (rf1 & RenderFlags.Update) {
containerRefreshEnd(); containerRefreshStart(1);
containerRefreshStart(2); {
{ if (ctx.sub1) {
if (ctx.sub2) { let rf1 = embeddedViewStart(0);
if (embeddedViewStart(0)) { if (rf1 & RenderFlags.Create) {
elementStart(0, 'button'); elementStart(0, 'button');
{ {
listener('click', function() { return ctx.counter2++; }); listener('click', function() { return ctx.counter1++; });
text(1, 'Click'); text(1, 'Click');
}
elementEnd();
}
embeddedViewEnd();
} }
elementEnd();
} }
embeddedViewEnd(); containerRefreshEnd();
containerRefreshStart(2);
{
if (ctx.sub2) {
let rf1 = embeddedViewStart(0);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'button');
{
listener('click', function() { return ctx.counter2++; });
text(1, 'Click');
}
elementEnd();
}
embeddedViewEnd();
}
}
containerRefreshEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
const ctx = {condition: true, counter1: 0, counter2: 0, sub1: true, sub2: true}; const ctx = {condition: true, counter1: 0, counter2: 0, sub1: true, sub2: true};

View File

@ -10,7 +10,7 @@ import {EventEmitter} from '@angular/core';
import {defineComponent, defineDirective} from '../../src/render3/index'; import {defineComponent, defineDirective} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, listener, text} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, listener, text} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {containerEl, renderToHtml} from './render_util'; import {containerEl, renderToHtml} from './render_util';
describe('outputs', () => { describe('outputs', () => {
@ -25,7 +25,7 @@ describe('outputs', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: ButtonToggle, type: ButtonToggle,
selectors: [['button-toggle']], selectors: [['button-toggle']],
template: function(ctx: any, cm: boolean) {}, template: function(rf: RenderFlags, ctx: any) {},
factory: () => buttonToggle = new ButtonToggle(), factory: () => buttonToggle = new ButtonToggle(),
outputs: {change: 'change', resetStream: 'reset'} outputs: {change: 'change', resetStream: 'reset'}
}); });
@ -51,7 +51,7 @@ describe('outputs', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: DestroyComp, type: DestroyComp,
selectors: [['destroy-comp']], selectors: [['destroy-comp']],
template: function(ctx: any, cm: boolean) {}, template: function(rf: RenderFlags, ctx: any) {},
factory: () => destroyComp = new DestroyComp() factory: () => destroyComp = new DestroyComp()
}); });
} }
@ -73,8 +73,8 @@ describe('outputs', () => {
it('should call component output function when event is emitted', () => { it('should call component output function when event is emitted', () => {
/** <button-toggle (change)="onChange()"></button-toggle> */ /** <button-toggle (change)="onChange()"></button-toggle> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button-toggle'); elementStart(0, 'button-toggle');
{ {
listener('change', function() { return ctx.onChange(); }); listener('change', function() { return ctx.onChange(); });
@ -96,8 +96,8 @@ describe('outputs', () => {
it('should support more than 1 output function on the same node', () => { it('should support more than 1 output function on the same node', () => {
/** <button-toggle (change)="onChange()" (reset)="onReset()"></button-toggle> */ /** <button-toggle (change)="onChange()" (reset)="onReset()"></button-toggle> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button-toggle'); elementStart(0, 'button-toggle');
{ {
listener('change', function() { return ctx.onChange(); }); listener('change', function() { return ctx.onChange(); });
@ -121,8 +121,8 @@ describe('outputs', () => {
it('should eval component output expression when event is emitted', () => { it('should eval component output expression when event is emitted', () => {
/** <button-toggle (change)="counter++"></button-toggle> */ /** <button-toggle (change)="counter++"></button-toggle> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button-toggle'); elementStart(0, 'button-toggle');
{ {
listener('change', function() { return ctx.counter++; }); listener('change', function() { return ctx.counter++; });
@ -149,24 +149,27 @@ describe('outputs', () => {
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (ctx.condition) { {
if (embeddedViewStart(0)) { if (ctx.condition) {
elementStart(0, 'button-toggle'); let rf1 = embeddedViewStart(0);
{ if (rf1 & RenderFlags.Create) {
listener('change', function() { return ctx.onChange(); }); elementStart(0, 'button-toggle');
{
listener('change', function() { return ctx.onChange(); });
}
elementEnd();
} }
elementEnd(); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
let counter = 0; let counter = 0;
@ -193,34 +196,38 @@ describe('outputs', () => {
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (ctx.condition) { {
if (embeddedViewStart(0)) { if (ctx.condition) {
container(0); let rf1 = embeddedViewStart(0);
} if (rf1 & RenderFlags.Create) {
containerRefreshStart(0); container(0);
{
if (ctx.condition2) {
if (embeddedViewStart(0)) {
elementStart(0, 'button-toggle');
{
listener('change', function() { return ctx.onChange(); });
}
elementEnd();
}
embeddedViewEnd();
} }
containerRefreshStart(0);
{
if (ctx.condition2) {
let rf1 = embeddedViewStart(0);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'button-toggle');
{
listener('change', function() { return ctx.onChange(); });
}
elementEnd();
}
embeddedViewEnd();
}
}
containerRefreshEnd();
embeddedViewEnd();
} }
containerRefreshEnd();
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
let counter = 0; let counter = 0;
@ -245,32 +252,35 @@ describe('outputs', () => {
* <destroy-comp></destroy-comp> * <destroy-comp></destroy-comp>
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (ctx.condition) { {
if (embeddedViewStart(0)) { if (ctx.condition) {
elementStart(0, 'button'); let rf1 = embeddedViewStart(0);
{ if (rf1 & RenderFlags.Create) {
listener('click', function() { return ctx.onClick(); }); elementStart(0, 'button');
text(1, 'Click me'); {
listener('click', function() { return ctx.onClick(); });
text(1, 'Click me');
}
elementEnd();
elementStart(2, 'button-toggle');
{
listener('change', function() { return ctx.onChange(); });
}
elementEnd();
elementStart(3, 'destroy-comp');
elementEnd();
} }
elementEnd(); embeddedViewEnd();
elementStart(2, 'button-toggle');
{
listener('change', function() { return ctx.onChange(); });
}
elementEnd();
elementStart(3, 'destroy-comp');
elementEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
let clickCounter = 0; let clickCounter = 0;
@ -299,8 +309,8 @@ describe('outputs', () => {
}); });
it('should fire event listeners along with outputs if they match', () => { it('should fire event listeners along with outputs if they match', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button', ['myButton', '']); elementStart(0, 'button', ['myButton', '']);
{ {
listener('click', function() { return ctx.onClick(); }); listener('click', function() { return ctx.onClick(); });
@ -324,8 +334,8 @@ describe('outputs', () => {
it('should work with two outputs of the same name', () => { it('should work with two outputs of the same name', () => {
/** <button-toggle (change)="onChange()" otherDir></button-toggle> */ /** <button-toggle (change)="onChange()" otherDir></button-toggle> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button-toggle', ['otherDir', '']); elementStart(0, 'button-toggle', ['otherDir', '']);
{ {
listener('change', function() { return ctx.onChange(); }); listener('change', function() { return ctx.onChange(); });
@ -359,15 +369,17 @@ describe('outputs', () => {
} }
/** <button-toggle (change)="onChange()" otherChangeDir [change]="change"></button-toggle> */ /** <button-toggle (change)="onChange()" otherChangeDir [change]="change"></button-toggle> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button-toggle', ['otherChangeDir', '']); elementStart(0, 'button-toggle', ['otherChangeDir', '']);
{ {
listener('change', function() { return ctx.onChange(); }); listener('change', function() { return ctx.onChange(); });
} }
elementEnd(); elementEnd();
} }
elementProperty(0, 'change', bind(ctx.change)); if (rf & RenderFlags.Update) {
elementProperty(0, 'change', bind(ctx.change));
}
} }
let counter = 0; let counter = 0;
@ -392,8 +404,8 @@ describe('outputs', () => {
* 'changeStream']} * 'changeStream']}
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button'); elementStart(0, 'button');
{ {
listener('click', function() { return ctx.onClick(); }); listener('click', function() { return ctx.onClick(); });
@ -402,29 +414,32 @@ describe('outputs', () => {
elementEnd(); elementEnd();
container(2); container(2);
} }
containerRefreshStart(2); if (rf & RenderFlags.Update) {
{ containerRefreshStart(2);
if (ctx.condition) { {
if (embeddedViewStart(0)) { if (ctx.condition) {
elementStart(0, 'button-toggle'); let rf1 = embeddedViewStart(0);
{ if (rf1 & RenderFlags.Create) {
listener('change', function() { return ctx.onChange(); }); elementStart(0, 'button-toggle');
{
listener('change', function() { return ctx.onChange(); });
}
elementEnd();
} }
elementEnd(); embeddedViewEnd();
} } else {
embeddedViewEnd(); if (embeddedViewStart(1)) {
} else { elementStart(0, 'div', ['otherDir', '']);
if (embeddedViewStart(1)) { {
elementStart(0, 'div', ['otherDir', '']); listener('change', function() { return ctx.onChange(); });
{ }
listener('change', function() { return ctx.onChange(); }); elementEnd();
} }
elementEnd(); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
let counter = 0; let counter = 0;

View File

@ -11,6 +11,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
import {defineDirective, definePipe} from '../../src/render3/definition'; import {defineDirective, definePipe} from '../../src/render3/definition';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, loadDirective, text, textBinding} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, loadDirective, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {pipe, pipeBind1, pipeBind3, pipeBind4, pipeBindV} from '../../src/render3/pipe'; import {pipe, pipeBind1, pipeBind3, pipeBind4, pipeBindV} from '../../src/render3/pipe';
import {RenderLog, getRendererFactory2, patchLoggingRenderer2} from './imported_renderer2'; import {RenderLog, getRendererFactory2, patchLoggingRenderer2} from './imported_renderer2';
@ -33,12 +34,14 @@ describe('pipe', () => {
const pipes = () => [CountingPipe, MultiArgPipe, CountingImpurePipe]; const pipes = () => [CountingPipe, MultiArgPipe, CountingImpurePipe];
it('should support interpolation', () => { it('should support interpolation', () => {
function Template(person: Person, cm: boolean) { function Template(rf: RenderFlags, person: Person) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
pipe(1, 'countingPipe'); pipe(1, 'countingPipe');
} }
textBinding(0, interpolation1('', pipeBind1(1, person.name), '')); if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', pipeBind1(1, person.name), ''));
}
} }
person.init('bob', null); person.init('bob', null);
@ -46,12 +49,14 @@ describe('pipe', () => {
}); });
it('should throw if pipe is not found', () => { it('should throw if pipe is not found', () => {
const App = createComponent('app', function(ctx: any, cm: boolean) { const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
pipe(1, 'randomPipeName'); pipe(1, 'randomPipeName');
} }
textBinding(0, interpolation1('', pipeBind1(1, ctx.value), '')); if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', pipeBind1(1, ctx.value), ''));
}
}, [], pipes); }, [], pipes);
expect(() => { expect(() => {
@ -87,27 +92,31 @@ describe('pipe', () => {
}); });
} }
function Template(ctx: string, cm: boolean) { function Template(rf: RenderFlags, ctx: string) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['myDir', '']); elementStart(0, 'div', ['myDir', '']);
pipe(1, 'double'); pipe(1, 'double');
elementEnd(); elementEnd();
} }
elementProperty(0, 'elprop', bind(pipeBind1(1, ctx))); if (rf & RenderFlags.Update) {
directive = loadDirective(0); elementProperty(0, 'elprop', bind(pipeBind1(1, ctx)));
directive = loadDirective(0);
}
} }
renderToHtml(Template, 'a', [MyDir], [DoublePipe]); renderToHtml(Template, 'a', [MyDir], [DoublePipe]);
expect(directive !.dirProp).toEqual('aa'); expect(directive !.dirProp).toEqual('aa');
}); });
it('should support arguments in pipes', () => { it('should support arguments in pipes', () => {
function Template(person: Person, cm: boolean) { function Template(rf: RenderFlags, person: Person) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
pipe(1, 'multiArgPipe'); pipe(1, 'multiArgPipe');
} }
textBinding( if (rf & RenderFlags.Update) {
0, interpolation1('', pipeBind3(1, person.name, 'one', person.address !.city), '')); textBinding(
0, interpolation1('', pipeBind3(1, person.name, 'one', person.address !.city), ''));
}
} }
person.init('value', new Address('two')); person.init('value', new Address('two'));
@ -115,14 +124,17 @@ describe('pipe', () => {
}); });
it('should support calling pipes with different number of arguments', () => { it('should support calling pipes with different number of arguments', () => {
function Template(person: Person, cm: boolean) { function Template(rf: RenderFlags, person: Person) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
pipe(1, 'multiArgPipe'); pipe(1, 'multiArgPipe');
pipe(2, 'multiArgPipe'); pipe(2, 'multiArgPipe');
} }
textBinding( if (rf & RenderFlags.Update) {
0, interpolation1('', pipeBind4(2, pipeBindV(1, [person.name, 'a', 'b']), 0, 1, 2), '')); textBinding(
0,
interpolation1('', pipeBind4(2, pipeBindV(1, [person.name, 'a', 'b']), 0, 1, 2), ''));
}
} }
person.init('value', null); person.init('value', null);
@ -141,13 +153,15 @@ describe('pipe', () => {
}); });
} }
function Template(person: Person, cm: boolean) { function Template(rf: RenderFlags, person: Person) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
pipe(1, 'identityPipe'); pipe(1, 'identityPipe');
elementEnd(); elementEnd();
} }
elementProperty(0, 'someProp', bind(pipeBind1(1, 'Megatron'))); if (rf & RenderFlags.Update) {
elementProperty(0, 'someProp', bind(pipeBind1(1, 'Megatron')));
}
} }
renderToHtml(Template, person, null, [IdentityPipe], rendererFactory2); renderToHtml(Template, person, null, [IdentityPipe], rendererFactory2);
@ -160,12 +174,14 @@ describe('pipe', () => {
describe('pure', () => { describe('pure', () => {
it('should call pure pipes only if the arguments change', () => { it('should call pure pipes only if the arguments change', () => {
function Template(person: Person, cm: boolean) { function Template(rf: RenderFlags, person: Person) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
pipe(1, 'countingPipe'); pipe(1, 'countingPipe');
} }
textBinding(0, interpolation1('', pipeBind1(1, person.name), '')); if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', pipeBind1(1, person.name), ''));
}
} }
// change from undefined -> null // change from undefined -> null
@ -187,12 +203,14 @@ describe('pipe', () => {
describe('impure', () => { describe('impure', () => {
it('should call impure pipes on each change detection run', () => { it('should call impure pipes on each change detection run', () => {
function Template(person: Person, cm: boolean) { function Template(rf: RenderFlags, person: Person) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
pipe(1, 'countingImpurePipe'); pipe(1, 'countingImpurePipe');
} }
textBinding(0, interpolation1('', pipeBind1(1, person.name), '')); if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', pipeBind1(1, person.name), ''));
}
} }
person.name = 'bob'; person.name = 'bob';
@ -201,8 +219,8 @@ describe('pipe', () => {
}); });
it('should not cache impure pipes', () => { it('should not cache impure pipes', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
pipe(1, 'countingImpurePipe'); pipe(1, 'countingImpurePipe');
elementEnd(); elementEnd();
@ -211,26 +229,30 @@ describe('pipe', () => {
elementEnd(); elementEnd();
container(4); container(4);
} }
elementProperty(0, 'someProp', bind(pipeBind1(1, true))); if (rf & RenderFlags.Update) {
elementProperty(2, 'someProp', bind(pipeBind1(3, true))); elementProperty(0, 'someProp', bind(pipeBind1(1, true)));
pipeInstances.push(load<CountingImpurePipe>(1), load(3)); elementProperty(2, 'someProp', bind(pipeBind1(3, true)));
containerRefreshStart(4); pipeInstances.push(load<CountingImpurePipe>(1), load(3));
{ containerRefreshStart(4);
for (let i of [1, 2]) { {
let cm1 = embeddedViewStart(1); for (let i of [1, 2]) {
{ let rf1 = embeddedViewStart(1);
if (cm1) { {
elementStart(0, 'div'); if (rf1 & RenderFlags.Create) {
pipe(1, 'countingImpurePipe'); elementStart(0, 'div');
elementEnd(); pipe(1, 'countingImpurePipe');
elementEnd();
}
if (rf1 & RenderFlags.Update) {
elementProperty(0, 'someProp', bind(pipeBind1(1, true)));
pipeInstances.push(load<CountingImpurePipe>(1));
}
} }
elementProperty(0, 'someProp', bind(pipeBind1(1, true))); embeddedViewEnd();
pipeInstances.push(load<CountingImpurePipe>(1));
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
const pipeInstances: CountingImpurePipe[] = []; const pipeInstances: CountingImpurePipe[] = [];
@ -261,25 +283,29 @@ describe('pipe', () => {
} }
it('should call ngOnDestroy on pipes', () => { it('should call ngOnDestroy on pipes', () => {
function Template(person: Person, cm: boolean) { function Template(rf: RenderFlags, person: Person) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
if (person.age > 20) { {
let cm1 = embeddedViewStart(1); if (person.age > 20) {
{ let rf1 = embeddedViewStart(1);
if (cm1) { {
text(0); if (rf1 & RenderFlags.Create) {
pipe(1, 'pipeWithOnDestroy'); text(0);
pipe(1, 'pipeWithOnDestroy');
}
if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', pipeBind1(1, person.age), ''));
}
} }
textBinding(0, interpolation1('', pipeBind1(1, person.age), '')); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
const pipes = [PipeWithOnDestroy]; const pipes = [PipeWithOnDestroy];

View File

@ -10,18 +10,20 @@ import {EventEmitter} from '@angular/core';
import {defineComponent, defineDirective, tick} from '../../src/render3/index'; import {defineComponent, defineDirective, tick} from '../../src/render3/index';
import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, listener, load, loadDirective, text, textBinding} from '../../src/render3/instructions'; import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, listener, load, loadDirective, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {ComponentFixture, renderToHtml} from './render_util'; import {ComponentFixture, renderToHtml} from './render_util';
describe('elementProperty', () => { describe('elementProperty', () => {
it('should support bindings to properties', () => { it('should support bindings to properties', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
elementEnd(); elementEnd();
} }
elementProperty(0, 'id', bind(ctx)); if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind(ctx));
}
} }
expect(renderToHtml(Template, 'testId')).toEqual('<span id="testId"></span>'); expect(renderToHtml(Template, 'testId')).toEqual('<span id="testId"></span>');
@ -37,12 +39,14 @@ describe('elementProperty', () => {
} }
} }
function Template(ctx: string, cm: boolean) { function Template(rf: RenderFlags, ctx: string) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
elementEnd(); elementEnd();
} }
elementProperty(0, 'id', cm ? expensive(ctx) : NO_CHANGE); if (rf & RenderFlags.Update) {
elementProperty(0, 'id', rf & RenderFlags.Create ? expensive(ctx) : NO_CHANGE);
}
} }
expect(renderToHtml(Template, 'cheapId')).toEqual('<span id="cheapId"></span>'); expect(renderToHtml(Template, 'cheapId')).toEqual('<span id="cheapId"></span>');
@ -50,12 +54,14 @@ describe('elementProperty', () => {
}); });
it('should support interpolation for properties', () => { it('should support interpolation for properties', () => {
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
elementEnd(); elementEnd();
} }
elementProperty(0, 'id', interpolation1('_', ctx, '_')); if (rf & RenderFlags.Update) {
elementProperty(0, 'id', interpolation1('_', ctx, '_'));
}
} }
expect(renderToHtml(Template, 'testId')).toEqual('<span id="_testId_"></span>'); expect(renderToHtml(Template, 'testId')).toEqual('<span id="_testId_"></span>');
@ -74,7 +80,7 @@ describe('elementProperty', () => {
const instance = loadDirective(dirIndex) as HostBindingComp; const instance = loadDirective(dirIndex) as HostBindingComp;
elementProperty(elIndex, 'id', bind(instance.id)); elementProperty(elIndex, 'id', bind(instance.id));
}, },
template: (ctx: HostBindingComp, cm: boolean) => {} template: (rf: RenderFlags, ctx: HostBindingComp) => {}
}); });
} }
@ -144,15 +150,16 @@ describe('elementProperty', () => {
it('should check input properties before setting (directives)', () => { it('should check input properties before setting (directives)', () => {
/** <button myButton otherDir [id]="id" [disabled]="isDisabled">Click me</button> */ /** <button myButton otherDir [id]="id" [disabled]="isDisabled">Click me</button> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button', ['otherDir', '', 'myButton', '']); elementStart(0, 'button', ['otherDir', '', 'myButton', '']);
{ text(1, 'Click me'); } { text(1, 'Click me'); }
elementEnd(); elementEnd();
} }
if (rf & RenderFlags.Update) {
elementProperty(0, 'disabled', bind(ctx.isDisabled)); elementProperty(0, 'disabled', bind(ctx.isDisabled));
elementProperty(0, 'id', bind(ctx.id)); elementProperty(0, 'id', bind(ctx.id));
}
} }
const ctx: any = {isDisabled: true, id: 0}; const ctx: any = {isDisabled: true, id: 0};
@ -172,15 +179,16 @@ describe('elementProperty', () => {
it('should support mixed element properties and input properties', () => { it('should support mixed element properties and input properties', () => {
/** <button myButton [id]="id" [disabled]="isDisabled">Click me</button> */ /** <button myButton [id]="id" [disabled]="isDisabled">Click me</button> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button', ['myButton', '']); elementStart(0, 'button', ['myButton', '']);
{ text(1, 'Click me'); } { text(1, 'Click me'); }
elementEnd(); elementEnd();
} }
if (rf & RenderFlags.Update) {
elementProperty(0, 'disabled', bind(ctx.isDisabled)); elementProperty(0, 'disabled', bind(ctx.isDisabled));
elementProperty(0, 'id', bind(ctx.id)); elementProperty(0, 'id', bind(ctx.id));
}
} }
const ctx: any = {isDisabled: true, id: 0}; const ctx: any = {isDisabled: true, id: 0};
@ -205,19 +213,21 @@ describe('elementProperty', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: Comp, type: Comp,
selectors: [['comp']], selectors: [['comp']],
template: function(ctx: any, cm: boolean) {}, template: function(rf: RenderFlags, ctx: any) {},
factory: () => comp = new Comp(), factory: () => comp = new Comp(),
inputs: {id: 'id'} inputs: {id: 'id'}
}); });
} }
/** <comp [id]="id"></comp> */ /** <comp [id]="id"></comp> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'comp'); elementStart(0, 'comp');
elementEnd(); elementEnd();
} }
elementProperty(0, 'id', bind(ctx.id)); if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind(ctx.id));
}
} }
const deps = [Comp]; const deps = [Comp];
@ -231,13 +241,15 @@ describe('elementProperty', () => {
it('should support two input properties with the same name', () => { it('should support two input properties with the same name', () => {
/** <button myButton otherDisabledDir [disabled]="isDisabled">Click me</button> */ /** <button myButton otherDisabledDir [disabled]="isDisabled">Click me</button> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button', ['myButton', '', 'otherDisabledDir', '']); elementStart(0, 'button', ['myButton', '', 'otherDisabledDir', '']);
{ text(1, 'Click me'); } { text(1, 'Click me'); }
elementEnd(); elementEnd();
} }
elementProperty(0, 'disabled', bind(ctx.isDisabled)); if (rf & RenderFlags.Update) {
elementProperty(0, 'disabled', bind(ctx.isDisabled));
}
} }
const ctx: any = {isDisabled: true}; const ctx: any = {isDisabled: true};
@ -255,8 +267,8 @@ describe('elementProperty', () => {
it('should set input property if there is an output first', () => { it('should set input property if there is an output first', () => {
/** <button otherDir [id]="id" (click)="onClick()">Click me</button> */ /** <button otherDir [id]="id" (click)="onClick()">Click me</button> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button', ['otherDir', '']); elementStart(0, 'button', ['otherDir', '']);
{ {
listener('click', ctx.onClick.bind(ctx)); listener('click', ctx.onClick.bind(ctx));
@ -264,7 +276,9 @@ describe('elementProperty', () => {
} }
elementEnd(); elementEnd();
} }
elementProperty(0, 'id', bind(ctx.id)); if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind(ctx.id));
}
} }
let counter = 0; let counter = 0;
@ -289,35 +303,43 @@ describe('elementProperty', () => {
* <button otherDir [id]="id3">Click me too</button> // inputs: {'id': [0, 'id']} * <button otherDir [id]="id3">Click me too</button> // inputs: {'id': [0, 'id']}
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'button', ['idDir', '']); elementStart(0, 'button', ['idDir', '']);
{ text(1, 'Click me'); } { text(1, 'Click me'); }
elementEnd(); elementEnd();
container(2); container(2);
} }
elementProperty(0, 'id', bind(ctx.id1)); if (rf & RenderFlags.Update) {
containerRefreshStart(2); elementProperty(0, 'id', bind(ctx.id1));
{ containerRefreshStart(2);
if (ctx.condition) { {
if (embeddedViewStart(0)) { if (ctx.condition) {
elementStart(0, 'button'); let rf0 = embeddedViewStart(0);
{ text(1, 'Click me too'); } if (rf0 & RenderFlags.Create) {
elementEnd(); elementStart(0, 'button');
{ text(1, 'Click me too'); }
elementEnd();
}
if (rf0 & RenderFlags.Update) {
elementProperty(0, 'id', bind(ctx.id2));
}
embeddedViewEnd();
} else {
let rf1 = embeddedViewStart(1);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'button', ['otherDir', '']);
{ text(1, 'Click me too'); }
elementEnd();
}
if (rf1 & RenderFlags.Update) {
elementProperty(0, 'id', bind(ctx.id3));
}
embeddedViewEnd();
} }
elementProperty(0, 'id', bind(ctx.id2));
embeddedViewEnd();
} else {
if (embeddedViewStart(1)) {
elementStart(0, 'button', ['otherDir', '']);
{ text(1, 'Click me too'); }
elementEnd();
}
elementProperty(0, 'id', bind(ctx.id3));
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
expect(renderToHtml(Template, {condition: true, id1: 'one', id2: 'two', id3: 'three'}, deps)) expect(renderToHtml(Template, {condition: true, id1: 'one', id2: 'two', id3: 'three'}, deps))
@ -367,8 +389,8 @@ describe('elementProperty', () => {
it('should set input property based on attribute if existing', () => { it('should set input property based on attribute if existing', () => {
/** <div role="button" myDir></div> */ /** <div role="button" myDir></div> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['role', 'button', 'myDir', '']); elementStart(0, 'div', ['role', 'button', 'myDir', '']);
elementEnd(); elementEnd();
} }
@ -381,12 +403,14 @@ describe('elementProperty', () => {
it('should set input property and attribute if both defined', () => { it('should set input property and attribute if both defined', () => {
/** <div role="button" [role]="role" myDir></div> */ /** <div role="button" [role]="role" myDir></div> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['role', 'button', 'myDir', '']); elementStart(0, 'div', ['role', 'button', 'myDir', '']);
elementEnd(); elementEnd();
} }
elementProperty(0, 'role', bind(ctx.role)); if (rf & RenderFlags.Update) {
elementProperty(0, 'role', bind(ctx.role));
}
} }
expect(renderToHtml(Template, {role: 'listbox'}, deps)) expect(renderToHtml(Template, {role: 'listbox'}, deps))
@ -400,8 +424,8 @@ describe('elementProperty', () => {
it('should set two directive input properties based on same attribute', () => { it('should set two directive input properties based on same attribute', () => {
/** <div role="button" myDir myDirB></div> */ /** <div role="button" myDir myDirB></div> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['role', 'button', 'myDir', '', 'myDirB', '']); elementStart(0, 'div', ['role', 'button', 'myDir', '', 'myDirB', '']);
elementEnd(); elementEnd();
} }
@ -416,8 +440,8 @@ describe('elementProperty', () => {
it('should process two attributes on same directive', () => { it('should process two attributes on same directive', () => {
/** <div role="button" dir="rtl" myDir></div> */ /** <div role="button" dir="rtl" myDir></div> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['role', 'button', 'dir', 'rtl', 'myDir', '']); elementStart(0, 'div', ['role', 'button', 'dir', 'rtl', 'myDir', '']);
elementEnd(); elementEnd();
} }
@ -432,8 +456,8 @@ describe('elementProperty', () => {
it('should process attributes and outputs properly together', () => { it('should process attributes and outputs properly together', () => {
/** <div role="button" (change)="onChange()" myDir></div> */ /** <div role="button" (change)="onChange()" myDir></div> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['role', 'button', 'myDir', '']); elementStart(0, 'div', ['role', 'button', 'myDir', '']);
{ listener('change', ctx.onChange.bind(ctx)); } { listener('change', ctx.onChange.bind(ctx)); }
elementEnd(); elementEnd();
@ -455,8 +479,8 @@ describe('elementProperty', () => {
* <div role="button" dir="rtl" myDir></div> * <div role="button" dir="rtl" myDir></div>
* <div role="listbox" myDirB></div> * <div role="listbox" myDirB></div>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['role', 'button', 'dir', 'rtl', 'myDir', '']); elementStart(0, 'div', ['role', 'button', 'dir', 'rtl', 'myDir', '']);
elementEnd(); elementEnd();
elementStart(1, 'div', ['role', 'listbox', 'myDirB', '']); elementStart(1, 'div', ['role', 'listbox', 'myDirB', '']);
@ -482,30 +506,33 @@ describe('elementProperty', () => {
* <div role="menu"></div> // initialInputs: [null] * <div role="menu"></div> // initialInputs: [null]
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['role', 'listbox', 'myDir', '']); elementStart(0, 'div', ['role', 'listbox', 'myDir', '']);
elementEnd(); elementEnd();
container(1); container(1);
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (ctx.condition) { {
if (embeddedViewStart(0)) { if (ctx.condition) {
elementStart(0, 'div', ['role', 'button', 'myDirB', '']); let rf1 = embeddedViewStart(0);
elementEnd(); if (rf1 & RenderFlags.Create) {
elementStart(0, 'div', ['role', 'button', 'myDirB', '']);
elementEnd();
}
embeddedViewEnd();
} else {
let rf2 = embeddedViewStart(1);
if (rf2 & RenderFlags.Create) {
elementStart(0, 'div', ['role', 'menu']);
elementEnd();
}
embeddedViewEnd();
} }
embeddedViewEnd();
} else {
if (embeddedViewStart(1)) {
elementStart(0, 'div', ['role', 'menu']);
{}
elementEnd();
}
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
expect(renderToHtml(Template, {condition: true}, deps)) expect(renderToHtml(Template, {condition: true}, deps))
@ -526,14 +553,16 @@ describe('elementProperty', () => {
type: Comp, type: Comp,
selectors: [['comp']], selectors: [['comp']],
/** <div role="button" dir #dir="myDir"></div> {{ dir.role }} */ /** <div role="button" dir #dir="myDir"></div> {{ dir.role }} */
template: function(ctx: any, cm: boolean) { template: function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['role', 'button', 'myDir', ''], ['dir', 'myDir']); elementStart(0, 'div', ['role', 'button', 'myDir', ''], ['dir', 'myDir']);
elementEnd(); elementEnd();
text(2); text(2);
} }
const tmp = load(1) as any; if (rf & RenderFlags.Update) {
textBinding(2, bind(tmp.role)); const tmp = load(1) as any;
textBinding(2, bind(tmp.role));
}
}, },
factory: () => new Comp(), factory: () => new Comp(),
directives: () => [MyDir] directives: () => [MyDir]
@ -545,21 +574,24 @@ describe('elementProperty', () => {
* <comp></comp> * <comp></comp>
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
for (let i = 0; i < 2; i++) { {
if (embeddedViewStart(0)) { for (let i = 0; i < 2; i++) {
elementStart(0, 'comp'); let rf1 = embeddedViewStart(0);
elementEnd(); if (rf1 & RenderFlags.Create) {
elementStart(0, 'comp');
elementEnd();
}
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
expect(renderToHtml(Template, {}, [Comp])) expect(renderToHtml(Template, {}, [Comp]))

View File

@ -7,6 +7,7 @@
*/ */
import {defineComponent} from '../../src/render3/index'; import {defineComponent} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {pureFunction1, pureFunction2, pureFunction3, pureFunction4, pureFunction5, pureFunction6, pureFunction7, pureFunction8, pureFunctionV} from '../../src/render3/pure_function'; import {pureFunction1, pureFunction2, pureFunction3, pureFunction4, pureFunction5, pureFunction6, pureFunction7, pureFunction8, pureFunctionV} from '../../src/render3/pure_function';
import {renderToHtml} from '../../test/render3/render_util'; import {renderToHtml} from '../../test/render3/render_util';
@ -20,7 +21,7 @@ describe('array literals', () => {
type: MyComp, type: MyComp,
selectors: [['my-comp']], selectors: [['my-comp']],
factory: function MyComp_Factory() { return myComp = new MyComp(); }, factory: function MyComp_Factory() { return myComp = new MyComp(); },
template: function MyComp_Template(ctx: MyComp, cm: boolean) {}, template: function MyComp_Template(rf: RenderFlags, ctx: MyComp) {},
inputs: {names: 'names'} inputs: {names: 'names'}
}); });
} }
@ -31,12 +32,14 @@ describe('array literals', () => {
const e0_ff = (v: any) => ['Nancy', v, 'Bess']; const e0_ff = (v: any) => ['Nancy', v, 'Bess'];
/** <my-comp [names]="['Nancy', customName, 'Bess']"></my-comp> */ /** <my-comp [names]="['Nancy', customName, 'Bess']"></my-comp> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp'); elementStart(0, 'my-comp');
elementEnd(); elementEnd();
} }
elementProperty(0, 'names', bind(pureFunction1(e0_ff, ctx.customName))); if (rf & RenderFlags.Update) {
elementProperty(0, 'names', bind(pureFunction1(e0_ff, ctx.customName)));
}
} }
renderToHtml(Template, {customName: 'Carson'}, directives); renderToHtml(Template, {customName: 'Carson'}, directives);
@ -71,7 +74,7 @@ describe('array literals', () => {
type: ManyPropComp, type: ManyPropComp,
selectors: [['many-prop-comp']], selectors: [['many-prop-comp']],
factory: function ManyPropComp_Factory() { return manyPropComp = new ManyPropComp(); }, factory: function ManyPropComp_Factory() { return manyPropComp = new ManyPropComp(); },
template: function ManyPropComp_Template(ctx: ManyPropComp, cm: boolean) {}, template: function ManyPropComp_Template(rf: RenderFlags, ctx: ManyPropComp) {},
inputs: {names1: 'names1', names2: 'names2'} inputs: {names1: 'names1', names2: 'names2'}
}); });
} }
@ -83,13 +86,15 @@ describe('array literals', () => {
* <many-prop-comp [names1]="['Nancy', customName]" [names2]="[customName2]"> * <many-prop-comp [names1]="['Nancy', customName]" [names2]="[customName2]">
* </many-prop-comp> * </many-prop-comp>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'many-prop-comp'); elementStart(0, 'many-prop-comp');
elementEnd(); elementEnd();
} }
elementProperty(0, 'names1', bind(pureFunction1(e0_ff, ctx.customName))); if (rf & RenderFlags.Update) {
elementProperty(0, 'names2', bind(pureFunction1(e0_ff_1, ctx.customName2))); elementProperty(0, 'names1', bind(pureFunction1(e0_ff, ctx.customName)));
elementProperty(0, 'names2', bind(pureFunction1(e0_ff_1, ctx.customName2)));
}
} }
const defs = [ManyPropComp]; const defs = [ManyPropComp];
@ -120,20 +125,22 @@ describe('array literals', () => {
type: ParentComp, type: ParentComp,
selectors: [['parent-comp']], selectors: [['parent-comp']],
factory: () => new ParentComp(), factory: () => new ParentComp(),
template: function(ctx: any, cm: boolean) { template: function(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp'); elementStart(0, 'my-comp');
myComps.push(loadDirective(0)); myComps.push(loadDirective(0));
elementEnd(); elementEnd();
} }
elementProperty(0, 'names', bind(ctx.someFn(pureFunction1(e0_ff, ctx.customName)))); if (rf & RenderFlags.Update) {
elementProperty(0, 'names', bind(ctx.someFn(pureFunction1(e0_ff, ctx.customName))));
}
}, },
directives: directives directives: directives
}); });
} }
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'parent-comp'); elementStart(0, 'parent-comp');
elementEnd(); elementEnd();
elementStart(1, 'parent-comp'); elementStart(1, 'parent-comp');
@ -159,12 +166,14 @@ describe('array literals', () => {
const e0_ff = (v1: any, v2: any) => ['Nancy', v1, 'Bess', v2]; const e0_ff = (v1: any, v2: any) => ['Nancy', v1, 'Bess', v2];
/** <my-comp [names]="['Nancy', customName, 'Bess', customName2]"></my-comp> */ /** <my-comp [names]="['Nancy', customName, 'Bess', customName2]"></my-comp> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp'); elementStart(0, 'my-comp');
elementEnd(); elementEnd();
} }
elementProperty(0, 'names', bind(pureFunction2(e0_ff, ctx.customName, ctx.customName2))); if (rf & RenderFlags.Update) {
elementProperty(0, 'names', bind(pureFunction2(e0_ff, ctx.customName, ctx.customName2)));
}
} }
renderToHtml(Template, {customName: 'Carson', customName2: 'Hannah'}, directives); renderToHtml(Template, {customName: 'Carson', customName2: 'Hannah'}, directives);
@ -212,8 +221,8 @@ describe('array literals', () => {
(v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any, (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any,
v8: any) => [v1, v2, v3, v4, v5, v6, v7, v8]; v8: any) => [v1, v2, v3, v4, v5, v6, v7, v8];
function Template(c: any, cm: boolean) { function Template(rf: RenderFlags, c: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp'); elementStart(0, 'my-comp');
f3Comp = loadDirective(0); f3Comp = loadDirective(0);
elementEnd(); elementEnd();
@ -233,14 +242,17 @@ describe('array literals', () => {
f8Comp = loadDirective(5); f8Comp = loadDirective(5);
elementEnd(); elementEnd();
} }
elementProperty(0, 'names', bind(pureFunction3(e0_ff, c[5], c[6], c[7]))); if (rf & RenderFlags.Update) {
elementProperty(1, 'names', bind(pureFunction4(e2_ff, c[4], c[5], c[6], c[7]))); elementProperty(0, 'names', bind(pureFunction3(e0_ff, c[5], c[6], c[7])));
elementProperty(2, 'names', bind(pureFunction5(e4_ff, c[3], c[4], c[5], c[6], c[7]))); elementProperty(1, 'names', bind(pureFunction4(e2_ff, c[4], c[5], c[6], c[7])));
elementProperty(3, 'names', bind(pureFunction6(e6_ff, c[2], c[3], c[4], c[5], c[6], c[7]))); elementProperty(2, 'names', bind(pureFunction5(e4_ff, c[3], c[4], c[5], c[6], c[7])));
elementProperty( elementProperty(3, 'names', bind(pureFunction6(e6_ff, c[2], c[3], c[4], c[5], c[6], c[7])));
4, 'names', bind(pureFunction7(e8_ff, c[1], c[2], c[3], c[4], c[5], c[6], c[7]))); elementProperty(
elementProperty( 4, 'names', bind(pureFunction7(e8_ff, c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
5, 'names', bind(pureFunction8(e10_ff, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]))); elementProperty(
5, 'names',
bind(pureFunction8(e10_ff, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
}
} }
renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], directives); renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], directives);
@ -279,14 +291,17 @@ describe('array literals', () => {
* <my-comp [names]="['start', v0, v1, v2, v3, {name: v4}, v5, v6, v7, v8, 'end']"> * <my-comp [names]="['start', v0, v1, v2, v3, {name: v4}, v5, v6, v7, v8, 'end']">
* </my-comp> * </my-comp>
*/ */
function Template(c: any, cm: boolean) { function Template(rf: RenderFlags, c: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp'); elementStart(0, 'my-comp');
elementEnd(); elementEnd();
} }
elementProperty(0, 'names', bind(pureFunctionV(e0_ff, [ if (rf & RenderFlags.Update) {
c[0], c[1], c[2], c[3], pureFunction1(e0_ff_1, c[4]), c[5], c[6], c[7], c[8] elementProperty(
]))); 0, 'names', bind(pureFunctionV(e0_ff, [
c[0], c[1], c[2], c[3], pureFunction1(e0_ff_1, c[4]), c[5], c[6], c[7], c[8]
])));
}
} }
expect(myComp !.names).toEqual([ expect(myComp !.names).toEqual([
@ -315,7 +330,7 @@ describe('object literals', () => {
type: ObjectComp, type: ObjectComp,
selectors: [['object-comp']], selectors: [['object-comp']],
factory: function ObjectComp_Factory() { return objectComp = new ObjectComp(); }, factory: function ObjectComp_Factory() { return objectComp = new ObjectComp(); },
template: function ObjectComp_Template(ctx: ObjectComp, cm: boolean) {}, template: function ObjectComp_Template(rf: RenderFlags, ctx: ObjectComp) {},
inputs: {config: 'config'} inputs: {config: 'config'}
}); });
} }
@ -326,12 +341,14 @@ describe('object literals', () => {
const e0_ff = (v: any) => { return {duration: 500, animation: v}; }; const e0_ff = (v: any) => { return {duration: 500, animation: v}; };
/** <object-comp [config]="{duration: 500, animation: name}"></object-comp> */ /** <object-comp [config]="{duration: 500, animation: name}"></object-comp> */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'object-comp'); elementStart(0, 'object-comp');
elementEnd(); elementEnd();
} }
elementProperty(0, 'config', bind(pureFunction1(e0_ff, ctx.name))); if (rf & RenderFlags.Update) {
elementProperty(0, 'config', bind(pureFunction1(e0_ff, ctx.name)));
}
} }
renderToHtml(Template, {name: 'slide'}, defs); renderToHtml(Template, {name: 'slide'}, defs);
@ -359,15 +376,17 @@ describe('object literals', () => {
* duration: duration }]}"> * duration: duration }]}">
* </object-comp> * </object-comp>
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'object-comp'); elementStart(0, 'object-comp');
elementEnd(); elementEnd();
} }
elementProperty( if (rf & RenderFlags.Update) {
0, 'config', elementProperty(
bind(pureFunction2( 0, 'config',
e0_ff, ctx.name, pureFunction1(e0_ff_1, pureFunction1(e0_ff_2, ctx.duration))))); bind(pureFunction2(
e0_ff, ctx.name, pureFunction1(e0_ff_1, pureFunction1(e0_ff_2, ctx.duration)))));
}
} }
renderToHtml(Template, {name: 'slide', duration: 100}, defs); renderToHtml(Template, {name: 'slide', duration: 100}, defs);
@ -419,25 +438,30 @@ describe('object literals', () => {
* </object-comp> * </object-comp>
* % } * % }
*/ */
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
container(0); container(0);
} }
containerRefreshStart(0); if (rf & RenderFlags.Update) {
{ containerRefreshStart(0);
for (let i = 0; i < 2; i++) { {
if (embeddedViewStart(0)) { for (let i = 0; i < 2; i++) {
elementStart(0, 'object-comp'); let rf1 = embeddedViewStart(0);
objectComps.push(loadDirective(0)); if (rf1 & RenderFlags.Create) {
elementEnd(); elementStart(0, 'object-comp');
objectComps.push(loadDirective(0));
elementEnd();
}
if (rf1 & RenderFlags.Update) {
elementProperty(
0, 'config',
bind(pureFunction2(e0_ff, ctx.configs[i].opacity, ctx.configs[i].duration)));
}
embeddedViewEnd();
} }
elementProperty(
0, 'config',
bind(pureFunction2(e0_ff, ctx.configs[i].opacity, ctx.configs[i].duration)));
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
} }
const e0_ff = (v1: any, v2: any) => { return {opacity: v1, duration: v2}; }; const e0_ff = (v1: any, v2: any) => { return {opacity: v1, duration: v2}; };

View File

@ -8,6 +8,7 @@
import {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF} from '../../src/render3/di'; import {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF} from '../../src/render3/di';
import {QueryList, defineComponent, detectChanges} from '../../src/render3/index'; import {QueryList, defineComponent, detectChanges} from '../../src/render3/index';
import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective} from '../../src/render3/instructions'; import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {query, queryRefresh} from '../../src/render3/query'; import {query, queryRefresh} from '../../src/render3/query';
import {createComponent, createDirective, renderComponent} from './render_util'; import {createComponent, createDirective, renderComponent} from './render_util';
@ -43,11 +44,11 @@ function isViewContainerRef(candidate: any): boolean {
describe('query', () => { describe('query', () => {
it('should project query children', () => { it('should project query children', () => {
const Child = createComponent('child', function(ctx: any, cm: boolean) {}); const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {});
let child1 = null; let child1 = null;
let child2 = null; let child2 = null;
const Cmp = createComponent('cmp', function(ctx: any, cm: boolean) { const Cmp = createComponent('cmp', function(rf: RenderFlags, ctx: any) {
/** /**
* <child> * <child>
* <child> * <child>
@ -59,7 +60,7 @@ describe('query', () => {
* } * }
*/ */
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, Child, false); query(0, Child, false);
query(1, Child, true); query(1, Child, true);
elementStart(2, 'child'); elementStart(2, 'child');
@ -71,8 +72,10 @@ describe('query', () => {
} }
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query0 = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(1)) && (ctx.query1 = tmp as QueryList<any>); queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query0 = tmp as QueryList<any>);
queryRefresh(tmp = load<QueryList<any>>(1)) && (ctx.query1 = tmp as QueryList<any>);
}
}, [Child]); }, [Child]);
const parent = renderComponent(Cmp); const parent = renderComponent(Cmp);
@ -91,14 +94,16 @@ describe('query', () => {
* @ViewChildren(Child, {read: ElementRef}) query; * @ViewChildren(Child, {read: ElementRef}) query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, Child, false, QUERY_READ_ELEMENT_REF); query(0, Child, false, QUERY_READ_ELEMENT_REF);
elToQuery = elementStart(1, 'div', ['child', '']); elToQuery = elementStart(1, 'div', ['child', '']);
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}, [Child]); }, [Child]);
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -119,15 +124,17 @@ describe('query', () => {
* @ViewChildren(Child, {read: OtherChild}) query; * @ViewChildren(Child, {read: OtherChild}) query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, Child, false, OtherChild); query(0, Child, false, OtherChild);
elementStart(1, 'div', ['child', '', 'otherChild', '']); elementStart(1, 'div', ['child', '', 'otherChild', '']);
{ otherChildInstance = loadDirective(1); } { otherChildInstance = loadDirective(1); }
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}, [Child, OtherChild]); }, [Child, OtherChild]);
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -145,14 +152,16 @@ describe('query', () => {
* @ViewChildren(Child, {read: OtherChild}) query; * @ViewChildren(Child, {read: OtherChild}) query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, Child, false, OtherChild); query(0, Child, false, OtherChild);
elementStart(1, 'div', ['child', '']); elementStart(1, 'div', ['child', '']);
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}, [Child, OtherChild]); }, [Child, OtherChild]);
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -173,16 +182,18 @@ describe('query', () => {
* @ViewChildren('foo') query; * @ViewChildren('foo') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_FROM_NODE); query(0, ['foo'], false, QUERY_READ_FROM_NODE);
elToQuery = elementStart(1, 'div', null, ['foo', '']); elToQuery = elementStart(1, 'div', null, ['foo', '']);
elementEnd(); elementEnd();
elementStart(3, 'div'); elementStart(3, 'div');
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -202,9 +213,9 @@ describe('query', () => {
* @ViewChildren('bar') barQuery; * @ViewChildren('bar') barQuery;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_FROM_NODE); query(0, ['foo'], false, QUERY_READ_FROM_NODE);
query(1, ['bar'], false, QUERY_READ_FROM_NODE); query(1, ['bar'], false, QUERY_READ_FROM_NODE);
elToQuery = elementStart(2, 'div', null, ['foo', '', 'bar', '']); elToQuery = elementStart(2, 'div', null, ['foo', '', 'bar', '']);
@ -212,8 +223,10 @@ describe('query', () => {
elementStart(5, 'div'); elementStart(5, 'div');
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.fooQuery = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(1)) && (ctx.barQuery = tmp as QueryList<any>); queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.fooQuery = tmp as QueryList<any>);
queryRefresh(tmp = load<QueryList<any>>(1)) && (ctx.barQuery = tmp as QueryList<any>);
}
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -239,9 +252,9 @@ describe('query', () => {
* @ViewChildren('foo,bar') query; * @ViewChildren('foo,bar') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE); query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE);
el1ToQuery = elementStart(1, 'div', null, ['foo', '']); el1ToQuery = elementStart(1, 'div', null, ['foo', '']);
elementEnd(); elementEnd();
@ -250,7 +263,9 @@ describe('query', () => {
el2ToQuery = elementStart(4, 'div', null, ['bar', '']); el2ToQuery = elementStart(4, 'div', null, ['bar', '']);
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -270,16 +285,18 @@ describe('query', () => {
* @ViewChildren('foo', {read: ElementRef}) query; * @ViewChildren('foo', {read: ElementRef}) query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_ELEMENT_REF); query(0, ['foo'], false, QUERY_READ_ELEMENT_REF);
elToQuery = elementStart(1, 'div', null, ['foo', '']); elToQuery = elementStart(1, 'div', null, ['foo', '']);
elementEnd(); elementEnd();
elementStart(3, 'div'); elementStart(3, 'div');
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -296,14 +313,16 @@ describe('query', () => {
* @ViewChildren('foo', {read: ViewContainerRef}) query; * @ViewChildren('foo', {read: ViewContainerRef}) query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_CONTAINER_REF); query(0, ['foo'], false, QUERY_READ_CONTAINER_REF);
elementStart(1, 'div', null, ['foo', '']); elementStart(1, 'div', null, ['foo', '']);
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -319,13 +338,15 @@ describe('query', () => {
* @ViewChildren('foo', {read: ViewContainerRef}) query; * @ViewChildren('foo', {read: ViewContainerRef}) query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_CONTAINER_REF); query(0, ['foo'], false, QUERY_READ_CONTAINER_REF);
container(1, undefined, undefined, undefined, ['foo', '']); container(1, undefined, undefined, undefined, ['foo', '']);
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -342,13 +363,15 @@ describe('query', () => {
* @ViewChildren('foo', {read: ElementRef}) query; * @ViewChildren('foo', {read: ElementRef}) query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_ELEMENT_REF); query(0, ['foo'], false, QUERY_READ_ELEMENT_REF);
container(1, undefined, undefined, undefined, ['foo', '']); container(1, undefined, undefined, undefined, ['foo', '']);
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -365,13 +388,15 @@ describe('query', () => {
* @ViewChildren('foo') query; * @ViewChildren('foo') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], undefined, QUERY_READ_FROM_NODE); query(0, ['foo'], undefined, QUERY_READ_FROM_NODE);
container(1, undefined, undefined, undefined, ['foo', '']); container(1, undefined, undefined, undefined, ['foo', '']);
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -388,13 +413,15 @@ describe('query', () => {
* @ViewChildren('foo', {read: TemplateRef}) query; * @ViewChildren('foo', {read: TemplateRef}) query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_TEMPLATE_REF); query(0, ['foo'], false, QUERY_READ_TEMPLATE_REF);
container(1, undefined, undefined, undefined, ['foo', '']); container(1, undefined, undefined, undefined, ['foo', '']);
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -404,7 +431,7 @@ describe('query', () => {
}); });
it('should read component instance if element queried for is a component host', () => { it('should read component instance if element queried for is a component host', () => {
const Child = createComponent('child', function(ctx: any, cm: boolean) {}); const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {});
let childInstance; let childInstance;
/** /**
@ -413,15 +440,17 @@ describe('query', () => {
* @ViewChildren('foo') query; * @ViewChildren('foo') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE); query(0, ['foo'], true, QUERY_READ_FROM_NODE);
elementStart(1, 'child', null, ['foo', '']); elementStart(1, 'child', null, ['foo', '']);
{ childInstance = loadDirective(0); } { childInstance = loadDirective(0); }
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}, [Child]); }, [Child]);
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -438,7 +467,7 @@ describe('query', () => {
type: Child, type: Child,
selectors: [['child']], selectors: [['child']],
factory: () => childInstance = new Child(), factory: () => childInstance = new Child(),
template: (ctx: Child, cm: boolean) => {}, template: (rf: RenderFlags, ctx: Child) => {},
exportAs: 'child' exportAs: 'child'
}); });
} }
@ -449,14 +478,16 @@ describe('query', () => {
* @ViewChildren('foo') query; * @ViewChildren('foo') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE); query(0, ['foo'], true, QUERY_READ_FROM_NODE);
elementStart(1, 'child', null, ['foo', 'child']); elementStart(1, 'child', null, ['foo', 'child']);
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}, [Child]); }, [Child]);
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -476,15 +507,17 @@ describe('query', () => {
* @ViewChildren('foo') query; * @ViewChildren('foo') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE); query(0, ['foo'], true, QUERY_READ_FROM_NODE);
elementStart(1, 'div', ['child', ''], ['foo', 'child']); elementStart(1, 'div', ['child', ''], ['foo', 'child']);
childInstance = loadDirective(0); childInstance = loadDirective(0);
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}, [Child]); }, [Child]);
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -504,9 +537,9 @@ describe('query', () => {
* @ViewChildren('foo, bar') query; * @ViewChildren('foo, bar') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo', 'bar'], true, QUERY_READ_FROM_NODE); query(0, ['foo', 'bar'], true, QUERY_READ_FROM_NODE);
elementStart(1, 'div', ['child1', '', 'child2', ''], ['foo', 'child1', 'bar', 'child2']); elementStart(1, 'div', ['child1', '', 'child2', ''], ['foo', 'child1', 'bar', 'child2']);
{ {
@ -515,7 +548,9 @@ describe('query', () => {
} }
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}, [Child1, Child2]); }, [Child1, Child2]);
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -536,17 +571,19 @@ describe('query', () => {
* @ViewChildren('bar') barQuery; * @ViewChildren('bar') barQuery;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE); query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(1, ['bar'], true, QUERY_READ_FROM_NODE); query(1, ['bar'], true, QUERY_READ_FROM_NODE);
elementStart(2, 'div', ['child', ''], ['foo', 'child', 'bar', 'child']); elementStart(2, 'div', ['child', ''], ['foo', 'child', 'bar', 'child']);
{ childInstance = loadDirective(0); } { childInstance = loadDirective(0); }
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.fooQuery = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(1)) && (ctx.barQuery = tmp as QueryList<any>); queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.fooQuery = tmp as QueryList<any>);
queryRefresh(tmp = load<QueryList<any>>(1)) && (ctx.barQuery = tmp as QueryList<any>);
}
}, [Child]); }, [Child]);
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -570,14 +607,16 @@ describe('query', () => {
* @ViewChildren('foo', {read: ElementRef}) query; * @ViewChildren('foo', {read: ElementRef}) query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], undefined, QUERY_READ_ELEMENT_REF); query(0, ['foo'], undefined, QUERY_READ_ELEMENT_REF);
div = elementStart(1, 'div', ['child', ''], ['foo', 'child']); div = elementStart(1, 'div', ['child', ''], ['foo', 'child']);
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}, [Child]); }, [Child]);
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -596,15 +635,17 @@ describe('query', () => {
* @ViewChildren('foo, bar') query; * @ViewChildren('foo, bar') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE); query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE);
div = elementStart(1, 'div', ['child', ''], ['foo', '', 'bar', 'child']); div = elementStart(1, 'div', ['child', ''], ['foo', '', 'bar', 'child']);
{ childInstance = loadDirective(0); } { childInstance = loadDirective(0); }
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}, [Child]); }, [Child]);
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -623,14 +664,16 @@ describe('query', () => {
* @ViewChildren('foo', {read: Child}) query; * @ViewChildren('foo', {read: Child}) query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], false, Child); query(0, ['foo'], false, Child);
elementStart(1, 'div', ['foo', '']); elementStart(1, 'div', ['foo', '']);
elementEnd(); elementEnd();
} }
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>); if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}
}, [Child]); }, [Child]);
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -652,27 +695,29 @@ describe('query', () => {
* @ViewChildren('foo') query; * @ViewChildren('foo') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE); query(0, ['foo'], true, QUERY_READ_FROM_NODE);
container(1); container(1);
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (ctx.exp) { {
let cm1 = embeddedViewStart(1); if (ctx.exp) {
{ let rf1 = embeddedViewStart(1);
if (cm1) { {
firstEl = elementStart(0, 'div', null, ['foo', '']); if (rf1 & RenderFlags.Create) {
elementEnd(); firstEl = elementStart(0, 'div', null, ['foo', '']);
elementEnd();
}
} }
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
} }
containerRefreshEnd();
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -702,9 +747,9 @@ describe('query', () => {
* @ViewChildren('foo') query; * @ViewChildren('foo') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE); query(0, ['foo'], true, QUERY_READ_FROM_NODE);
firstEl = elementStart(1, 'span', null, ['foo', '']); firstEl = elementStart(1, 'span', null, ['foo', '']);
elementEnd(); elementEnd();
@ -712,21 +757,23 @@ describe('query', () => {
lastEl = elementStart(4, 'span', null, ['foo', '']); lastEl = elementStart(4, 'span', null, ['foo', '']);
elementEnd(); elementEnd();
} }
containerRefreshStart(3); if (rf & RenderFlags.Update) {
{ containerRefreshStart(3);
if (ctx.exp) { {
let cm1 = embeddedViewStart(1); if (ctx.exp) {
{ let rf1 = embeddedViewStart(1);
if (cm1) { {
viewEl = elementStart(0, 'div', null, ['foo', '']); if (rf1 & RenderFlags.Create) {
elementEnd(); viewEl = elementStart(0, 'div', null, ['foo', '']);
elementEnd();
}
} }
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
} }
containerRefreshEnd();
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -762,37 +809,39 @@ describe('query', () => {
* @ViewChildren('foo') query; * @ViewChildren('foo') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE); query(0, ['foo'], true, QUERY_READ_FROM_NODE);
container(1); container(1);
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (ctx.exp1) { {
let cm1 = embeddedViewStart(0); if (ctx.exp1) {
{ let rf0 = embeddedViewStart(0);
if (cm1) { {
firstEl = elementStart(0, 'div', null, ['foo', '']); if (rf0 & RenderFlags.Create) {
elementEnd(); firstEl = elementStart(0, 'div', null, ['foo', '']);
elementEnd();
}
} }
embeddedViewEnd();
} }
embeddedViewEnd(); if (ctx.exp2) {
} let rf1 = embeddedViewStart(1);
if (ctx.exp2) { {
let cm1 = embeddedViewStart(1); if (rf1 & RenderFlags.Create) {
{ lastEl = elementStart(0, 'span', null, ['foo', '']);
if (cm1) { elementEnd();
lastEl = elementStart(0, 'span', null, ['foo', '']); }
elementEnd();
} }
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
} }
containerRefreshEnd();
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -824,42 +873,46 @@ describe('query', () => {
* @ViewChildren('foo') query; * @ViewChildren('foo') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE); query(0, ['foo'], true, QUERY_READ_FROM_NODE);
container(1); container(1);
} }
containerRefreshStart(1); if (rf & RenderFlags.Update) {
{ containerRefreshStart(1);
if (ctx.exp1) { {
let cm1 = embeddedViewStart(0); if (ctx.exp1) {
{ let rf0 = embeddedViewStart(0);
if (cm1) {
firstEl = elementStart(0, 'div', null, ['foo', '']);
elementEnd();
container(2);
}
containerRefreshStart(2);
{ {
if (ctx.exp2) { if (rf0 & RenderFlags.Create) {
let cm2 = embeddedViewStart(0); firstEl = elementStart(0, 'div', null, ['foo', '']);
elementEnd();
container(2);
}
if (rf0 & RenderFlags.Update) {
containerRefreshStart(2);
{ {
if (cm2) { if (ctx.exp2) {
lastEl = elementStart(0, 'span', null, ['foo', '']); let rf2 = embeddedViewStart(0);
elementEnd(); {
if (rf2) {
lastEl = elementStart(0, 'span', null, ['foo', '']);
elementEnd();
}
}
embeddedViewEnd();
} }
} }
embeddedViewEnd(); containerRefreshEnd();
} }
} }
containerRefreshEnd(); embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
} }
containerRefreshEnd();
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);
@ -888,31 +941,33 @@ describe('query', () => {
* @ViewChildren('foo') query; * @ViewChildren('foo') query;
* } * }
*/ */
const Cmpt = createComponent('cmpt', function(ctx: any, cm: boolean) { const Cmpt = createComponent('cmpt', function(rf: RenderFlags, ctx: any) {
let tmp: any; let tmp: any;
if (cm) { if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE); query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(1, ['foo'], false, QUERY_READ_FROM_NODE); query(1, ['foo'], false, QUERY_READ_FROM_NODE);
container(2); container(2);
elementStart(3, 'span', null, ['foo', '']); elementStart(3, 'span', null, ['foo', '']);
elementEnd(); elementEnd();
} }
containerRefreshStart(2); if (rf & RenderFlags.Update) {
{ containerRefreshStart(2);
if (ctx.exp) { {
let cm1 = embeddedViewStart(0); if (ctx.exp) {
{ let rf0 = embeddedViewStart(0);
if (cm1) { {
elementStart(0, 'div', null, ['foo', '']); if (rf0 & RenderFlags.Create) {
elementEnd(); elementStart(0, 'div', null, ['foo', '']);
elementEnd();
}
} }
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.deep = tmp as QueryList<any>);
queryRefresh(tmp = load<QueryList<any>>(1)) && (ctx.shallow = tmp as QueryList<any>);
} }
containerRefreshEnd();
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.deep = tmp as QueryList<any>);
queryRefresh(tmp = load<QueryList<any>>(1)) && (ctx.shallow = tmp as QueryList<any>);
}); });
const cmptInstance = renderComponent(Cmpt); const cmptInstance = renderComponent(Cmpt);

View File

@ -10,7 +10,7 @@ import {stringifyElement} from '@angular/platform-browser/testing/src/browser_ut
import {CreateComponentOptions} from '../../src/render3/component'; import {CreateComponentOptions} from '../../src/render3/component';
import {extractDirectiveDef, extractPipeDef} from '../../src/render3/definition'; import {extractDirectiveDef, extractPipeDef} from '../../src/render3/definition';
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, PublicFeature, defineComponent, defineDirective, renderComponent as _renderComponent, tick} from '../../src/render3/index'; import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, PublicFeature, RenderFlags, defineComponent, defineDirective, renderComponent as _renderComponent, tick} from '../../src/render3/index';
import {NG_HOST_SYMBOL, renderTemplate} from '../../src/render3/instructions'; import {NG_HOST_SYMBOL, renderTemplate} from '../../src/render3/instructions';
import {DirectiveDefList, DirectiveDefListOrFactory, DirectiveTypesOrFactory, PipeDef, PipeDefList, PipeDefListOrFactory, PipeTypesOrFactory} from '../../src/render3/interfaces/definition'; import {DirectiveDefList, DirectiveDefListOrFactory, DirectiveTypesOrFactory, PipeDef, PipeDefList, PipeDefListOrFactory, PipeTypesOrFactory} from '../../src/render3/interfaces/definition';
import {LElementNode} from '../../src/render3/interfaces/node'; import {LElementNode} from '../../src/render3/interfaces/node';
@ -63,11 +63,13 @@ export class TemplateFixture extends BaseFixture {
super(); super();
this._directiveDefs = toDefs(directives, extractDirectiveDef); this._directiveDefs = toDefs(directives, extractDirectiveDef);
this._pipeDefs = toDefs(pipes, extractPipeDef); this._pipeDefs = toDefs(pipes, extractPipeDef);
this.hostNode = renderTemplate(this.hostElement, (ctx: any, cm: boolean) => { this.hostNode = renderTemplate(this.hostElement, (rf: RenderFlags, ctx: any) => {
if (cm) { if (rf & RenderFlags.Create) {
this.createBlock(); this.createBlock();
} }
this.updateBlock(); if (rf & RenderFlags.Update) {
this.updateBlock();
}
}, null !, domRendererFactory3, null, this._directiveDefs, this._pipeDefs); }, null !, domRendererFactory3, null, this._directiveDefs, this._pipeDefs);
} }

View File

@ -12,6 +12,7 @@ import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/brow
import {RendererType2, ViewEncapsulation} from '../../src/core'; import {RendererType2, ViewEncapsulation} from '../../src/core';
import {defineComponent, detectChanges} from '../../src/render3/index'; import {defineComponent, detectChanges} from '../../src/render3/index';
import {bind, elementEnd, elementProperty, elementStart, listener, text, tick} from '../../src/render3/instructions'; import {bind, elementEnd, elementProperty, elementStart, listener, text, tick} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {createRendererType2} from '../../src/view/index'; import {createRendererType2} from '../../src/view/index';
import {getAnimationRendererFactory2, getRendererFactory2} from './imported_renderer2'; import {getAnimationRendererFactory2, getRendererFactory2} from './imported_renderer2';
@ -32,9 +33,9 @@ describe('renderer factory lifecycle', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: SomeComponent, type: SomeComponent,
selectors: [['some-component']], selectors: [['some-component']],
template: function(ctx: SomeComponent, cm: boolean) { template: function(rf: RenderFlags, ctx: SomeComponent) {
logs.push('component'); logs.push('component');
if (cm) { if (rf & RenderFlags.Create) {
text(0, 'foo'); text(0, 'foo');
} }
}, },
@ -46,25 +47,25 @@ describe('renderer factory lifecycle', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: SomeComponentWhichThrows, type: SomeComponentWhichThrows,
selectors: [['some-component-with-Error']], selectors: [['some-component-with-Error']],
template: function(ctx: SomeComponentWhichThrows, cm: boolean) { template: function(rf: RenderFlags, ctx: SomeComponentWhichThrows) {
throw(new Error('SomeComponentWhichThrows threw')); throw(new Error('SomeComponentWhichThrows threw'));
}, },
factory: () => new SomeComponentWhichThrows factory: () => new SomeComponentWhichThrows
}); });
} }
function Template(ctx: any, cm: boolean) { function Template(rf: RenderFlags, ctx: any) {
logs.push('function'); logs.push('function');
if (cm) { if (rf & RenderFlags.Create) {
text(0, 'bar'); text(0, 'bar');
} }
} }
const directives = [SomeComponent, SomeComponentWhichThrows]; const directives = [SomeComponent, SomeComponentWhichThrows];
function TemplateWithComponent(ctx: any, cm: boolean) { function TemplateWithComponent(rf: RenderFlags, ctx: any) {
logs.push('function_with_component'); logs.push('function_with_component');
if (cm) { if (rf & RenderFlags.Create) {
text(0, 'bar'); text(0, 'bar');
elementStart(1, 'some-component'); elementStart(1, 'some-component');
elementEnd(); elementEnd();
@ -125,8 +126,8 @@ describe('animation renderer factory', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: SomeComponent, type: SomeComponent,
selectors: [['some-component']], selectors: [['some-component']],
template: function(ctx: SomeComponent, cm: boolean) { template: function(rf: RenderFlags, ctx: SomeComponent) {
if (cm) { if (rf & RenderFlags.Create) {
text(0, 'foo'); text(0, 'foo');
} }
}, },
@ -142,8 +143,8 @@ describe('animation renderer factory', () => {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: SomeComponentWithAnimation, type: SomeComponentWithAnimation,
selectors: [['some-component']], selectors: [['some-component']],
template: function(ctx: SomeComponentWithAnimation, cm: boolean) { template: function(rf: RenderFlags, ctx: SomeComponentWithAnimation) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'div'); elementStart(0, 'div');
{ {
listener('@myAnimation.start', ctx.callback.bind(ctx)); listener('@myAnimation.start', ctx.callback.bind(ctx));
@ -152,7 +153,9 @@ describe('animation renderer factory', () => {
} }
elementEnd(); elementEnd();
} }
elementProperty(0, '@myAnimation', bind(ctx.exp)); if (rf & RenderFlags.Update) {
elementProperty(0, '@myAnimation', bind(ctx.exp));
}
}, },
factory: () => new SomeComponentWithAnimation, factory: () => new SomeComponentWithAnimation,
rendererType: createRendererType2({ rendererType: createRendererType2({

View File

@ -10,6 +10,7 @@ import {Component, Directive, TemplateRef, ViewContainerRef} from '../../src/cor
import {getOrCreateNodeInjectorForNode, getOrCreateTemplateRef} from '../../src/render3/di'; import {getOrCreateNodeInjectorForNode, getOrCreateTemplateRef} from '../../src/render3/di';
import {defineComponent, defineDirective, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index'; import {defineComponent, defineDirective, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, loadDirective, projection, projectionDef, text, textBinding} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, loadDirective, projection, projectionDef, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {ComponentFixture, TemplateFixture} from './render_util'; import {ComponentFixture, TemplateFixture} from './render_util';
@ -34,11 +35,13 @@ describe('ViewContainerRef', () => {
} }
describe('API', () => { describe('API', () => {
function embeddedTemplate(ctx: any, cm: boolean) { function embeddedTemplate(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
text(0); text(0);
} }
textBinding(0, ctx.name); if (rf & RenderFlags.Update) {
textBinding(0, bind(ctx.name));
}
} }
function createView(s: string, index?: number) { function createView(s: string, index?: number) {
@ -99,7 +102,7 @@ describe('ViewContainerRef', () => {
type: HeaderComponent, type: HeaderComponent,
selectors: [['header-cmp']], selectors: [['header-cmp']],
factory: () => new HeaderComponent(), factory: () => new HeaderComponent(),
template: (cmp: HeaderComponent, cm: boolean) => {} template: (rf: RenderFlags, cmp: HeaderComponent) => {}
}); });
} }
@ -143,7 +146,8 @@ describe('ViewContainerRef', () => {
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0))); const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(0, 'tplRef', bind(tplRef)); elementProperty(0, 'tplRef', bind(tplRef));
containerRefreshStart(0); containerRefreshStart(0);
if (embeddedViewStart(1)) { let rf1 = embeddedViewStart(1);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'header'); elementStart(0, 'header');
elementEnd(); elementEnd();
} }
@ -195,14 +199,14 @@ describe('ViewContainerRef', () => {
remove(index?: number) { this._vcRef.remove(index); } remove(index?: number) { this._vcRef.remove(index); }
} }
function EmbeddedTemplateA(ctx: any, cm: boolean) { function EmbeddedTemplateA(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
text(0, 'A'); text(0, 'A');
} }
} }
function EmbeddedTemplateB(ctx: any, cm: boolean) { function EmbeddedTemplateB(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
text(0, 'B'); text(0, 'B');
} }
} }
@ -219,8 +223,8 @@ describe('ViewContainerRef', () => {
type: TestComponent, type: TestComponent,
selectors: [['test-cmp']], selectors: [['test-cmp']],
factory: () => new TestComponent(), factory: () => new TestComponent(),
template: (cmp: TestComponent, cm: boolean) => { template: (rf: RenderFlags, cmp: TestComponent) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0, 'before|'); text(0, 'before|');
container(1, EmbeddedTemplateA, undefined, ['testdir', '']); container(1, EmbeddedTemplateA, undefined, ['testdir', '']);
container(2, EmbeddedTemplateB, undefined, ['testdir', '']); container(2, EmbeddedTemplateB, undefined, ['testdir', '']);
@ -261,8 +265,8 @@ describe('ViewContainerRef', () => {
remove(index?: number) { this._vcRef.remove(index); } remove(index?: number) { this._vcRef.remove(index); }
} }
function EmbeddedTemplateA(ctx: any, cm: boolean) { function EmbeddedTemplateA(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
text(0, 'A'); text(0, 'A');
} }
} }
@ -282,26 +286,28 @@ describe('ViewContainerRef', () => {
type: TestComponent, type: TestComponent,
selectors: [['test-cmp']], selectors: [['test-cmp']],
factory: () => new TestComponent(), factory: () => new TestComponent(),
template: (cmp: TestComponent, cm: boolean) => { template: (rf: RenderFlags, cmp: TestComponent) => {
if (cm) { if (rf & RenderFlags.Create) {
text(0, 'before|'); text(0, 'before|');
container(1, EmbeddedTemplateA, undefined, ['testdir', '']); container(1, EmbeddedTemplateA, undefined, ['testdir', '']);
container(2); container(2);
text(3, '|after'); text(3, '|after');
} }
containerRefreshStart(2); if (rf & RenderFlags.Update) {
{ containerRefreshStart(2);
if (cmp.condition) { {
let cm1 = embeddedViewStart(0); if (cmp.condition) {
{ let rf1 = embeddedViewStart(0);
if (cm1) { {
text(0, 'B'); if (rf1 & RenderFlags.Create) {
text(0, 'B');
}
} }
embeddedViewEnd();
} }
embeddedViewEnd();
} }
containerRefreshEnd();
} }
containerRefreshEnd();
}, },
directives: [TestDirective] directives: [TestDirective]
}); });
@ -456,8 +462,8 @@ describe('ViewContainerRef', () => {
}); });
describe('projection', () => { describe('projection', () => {
function embeddedTemplate(ctx: any, cm: boolean) { function embeddedTemplate(rf: RenderFlags, ctx: any) {
if (cm) { if (rf & RenderFlags.Create) {
elementStart(0, 'span'); elementStart(0, 'span');
text(1); text(1);
elementEnd(); elementEnd();
@ -472,8 +478,8 @@ describe('ViewContainerRef', () => {
type: Child, type: Child,
selectors: [['child']], selectors: [['child']],
factory: () => new Child(), factory: () => new Child(),
template: (cmp: Child, cm: boolean) => { template: (rf: RenderFlags, cmp: Child) => {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0); projectionDef(0);
elementStart(1, 'div'); elementStart(1, 'div');
{ projection(2, 0); } { projection(2, 0); }
@ -497,8 +503,8 @@ describe('ViewContainerRef', () => {
type: Parent, type: Parent,
selectors: [['parent']], selectors: [['parent']],
factory: () => new Parent(), factory: () => new Parent(),
template: (cmp: Parent, cm: boolean) => { template: (rf: RenderFlags, cmp: Parent) => {
if (cm) { if (rf & RenderFlags.Create) {
container(0, embeddedTemplate); container(0, embeddedTemplate);
elementStart(1, 'child'); elementStart(1, 'child');
elementStart(2, 'header', ['vcref', '']); elementStart(2, 'header', ['vcref', '']);
@ -506,9 +512,12 @@ describe('ViewContainerRef', () => {
elementEnd(); elementEnd();
elementEnd(); elementEnd();
} }
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0))); let tplRef: any;
elementProperty(2, 'tplRef', bind(tplRef)); if (rf & RenderFlags.Update) {
elementProperty(2, 'name', bind(cmp.name)); tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(2, 'tplRef', bind(tplRef));
elementProperty(2, 'name', bind(cmp.name));
}
}, },
directives: [Child, DirectiveWithVCRef] directives: [Child, DirectiveWithVCRef]
}); });
@ -535,8 +544,8 @@ describe('ViewContainerRef', () => {
type: ChildWithSelector, type: ChildWithSelector,
selectors: [['child-with-selector']], selectors: [['child-with-selector']],
factory: () => new ChildWithSelector(), factory: () => new ChildWithSelector(),
template: (cmp: ChildWithSelector, cm: boolean) => { template: (rf: RenderFlags, cmp: ChildWithSelector) => {
if (cm) { if (rf & RenderFlags.Create) {
projectionDef(0, [[['header']]], ['header']); projectionDef(0, [[['header']]], ['header']);
elementStart(1, 'first'); elementStart(1, 'first');
{ projection(2, 0, 1); } { projection(2, 0, 1); }
@ -545,7 +554,8 @@ describe('ViewContainerRef', () => {
{ projection(4, 0); } { projection(4, 0); }
elementEnd(); elementEnd();
} }
} },
directives: [ChildWithSelector, DirectiveWithVCRef]
}); });
} }
@ -565,8 +575,9 @@ describe('ViewContainerRef', () => {
type: Parent, type: Parent,
selectors: [['parent']], selectors: [['parent']],
factory: () => new Parent(), factory: () => new Parent(),
template: (cmp: Parent, cm: boolean) => { template: (rf: RenderFlags, cmp: Parent) => {
if (cm) { let tplRef: any;
if (rf & RenderFlags.Create) {
container(0, embeddedTemplate); container(0, embeddedTemplate);
elementStart(1, 'child-with-selector'); elementStart(1, 'child-with-selector');
elementStart(2, 'header', ['vcref', '']); elementStart(2, 'header', ['vcref', '']);
@ -574,9 +585,11 @@ describe('ViewContainerRef', () => {
elementEnd(); elementEnd();
elementEnd(); elementEnd();
} }
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0))); if (rf & RenderFlags.Update) {
elementProperty(2, 'tplRef', bind(tplRef)); tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(2, 'name', bind(cmp.name)); elementProperty(2, 'tplRef', bind(tplRef));
elementProperty(2, 'name', bind(cmp.name));
}
}, },
directives: [ChildWithSelector, DirectiveWithVCRef] directives: [ChildWithSelector, DirectiveWithVCRef]
}); });
@ -611,8 +624,9 @@ describe('ViewContainerRef', () => {
type: Parent, type: Parent,
selectors: [['parent']], selectors: [['parent']],
factory: () => new Parent(), factory: () => new Parent(),
template: (cmp: Parent, cm: boolean) => { template: (rf: RenderFlags, cmp: Parent) => {
if (cm) { let tplRef: any;
if (rf & RenderFlags.Create) {
container(0, embeddedTemplate); container(0, embeddedTemplate);
elementStart(1, 'child-with-selector'); elementStart(1, 'child-with-selector');
elementStart(2, 'footer', ['vcref', '']); elementStart(2, 'footer', ['vcref', '']);
@ -620,9 +634,11 @@ describe('ViewContainerRef', () => {
elementEnd(); elementEnd();
elementEnd(); elementEnd();
} }
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0))); if (rf & RenderFlags.Update) {
elementProperty(2, 'tplRef', bind(tplRef)); tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(2, 'name', bind(cmp.name)); elementProperty(2, 'tplRef', bind(tplRef));
elementProperty(2, 'name', bind(cmp.name));
}
}, },
directives: [ChildWithSelector, DirectiveWithVCRef] directives: [ChildWithSelector, DirectiveWithVCRef]
}); });