feat(ivy): add support for local refs on ng-template (#25482)

PR Close #25482
This commit is contained in:
Pawel Kozlowski 2018-08-14 16:25:01 +02:00 committed by Jason Aden
parent 07d8d3994c
commit 31f0f5b3c3
10 changed files with 213 additions and 129 deletions

View File

@ -28,6 +28,7 @@ export {
injectAttribute as ɵinjectAttribute,
getFactoryOf as ɵgetFactoryOf,
getInheritedFactory as ɵgetInheritedFactory,
templateRefExtractor as ɵtemplateRefExtractor,
PublicFeature as ɵPublicFeature,
InheritDefinitionFeature as ɵInheritDefinitionFeature,
NgOnChangesFeature as ɵNgOnChangesFeature,

View File

@ -27,7 +27,7 @@ import {addToViewTree, assertPreviousIsParent, createEmbeddedViewNode, createLCo
import {VIEWS} from './interfaces/container';
import {DirectiveDefInternal, RenderFlags} from './interfaces/definition';
import {LInjector} from './interfaces/injector';
import {AttributeMarker, LContainerNode, LElementContainerNode, LElementNode, LNode, LViewNode, TContainerNode, TElementNode, TNodeFlags, TNodeType} from './interfaces/node';
import {AttributeMarker, LContainerNode, LElementContainerNode, LElementNode, LNode, LNodeWithLocalRefs, LViewNode, TContainerNode, TElementNode, TNodeFlags, TNodeType} from './interfaces/node';
import {LQueries, QueryReadType} from './interfaces/query';
import {Renderer3} from './interfaces/renderer';
import {DIRECTIVES, HOST_NODE, INJECTOR, LViewData, QUERIES, RENDERER, TVIEW, TView} from './interfaces/view';
@ -814,3 +814,11 @@ class TemplateRef<T> implements viewEngine_TemplateRef<T> {
return viewRef;
}
}
/**
* Retrieves `TemplateRef` instance from `Injector` when a local reference is placed on the
* `<ng-template>` element.
*/
export function templateRefExtractor(lNode: LNodeWithLocalRefs) {
return getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(lNode));
}

View File

@ -14,7 +14,7 @@ import {PublicFeature} from './features/public_feature';
import {BaseDef, ComponentDef, ComponentDefInternal, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveDefInternal, DirectiveType, PipeDef} from './interfaces/definition';
export {ComponentFactory, ComponentFactoryResolver, ComponentRef, WRAP_RENDERER_FACTORY2} from './component_ref';
export {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, getFactoryOf, getInheritedFactory, injectAttribute, injectChangeDetectorRef, injectComponentFactoryResolver, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di';
export {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, getFactoryOf, getInheritedFactory, injectAttribute, injectChangeDetectorRef, injectComponentFactoryResolver, injectElementRef, injectTemplateRef, injectViewContainerRef, templateRefExtractor} from './di';
export {RenderFlags} from './interfaces/definition';
export {CssSelectorList} from './interfaces/projection';

View File

@ -18,10 +18,10 @@ import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} fro
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
import {ComponentDefInternal, ComponentQuery, ComponentTemplate, DirectiveDefInternal, DirectiveDefListOrFactory, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
import {LInjector} from './interfaces/injector';
import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LElementContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node';
import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LElementContainerNode, LElementNode, LNode, LNodeWithLocalRefs, LProjectionNode, LTextNode, LViewNode, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node';
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
import {LQueries} from './interfaces/query';
import {ProceduralRenderer3, RComment, RElement, RText, Renderer3, RendererFactory3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
import {BINDING_INDEX, CLEANUP, CONTENT_QUERIES, CONTEXT, CurrentMatchesList, DECLARATION_VIEW, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RootContext, SANITIZER, TAIL, TData, TVIEW, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
import {appendChild, appendProjectedNode, canInsertNativeNode, createTextNode, findComponentHost, getChildLNode, getLViewChild, getNextLNode, getParentLNode, insertView, removeView} from './node_manipulation';
@ -734,7 +734,7 @@ export function elementContainerStart(
createLNode(index, TNodeType.ElementContainer, native, null, attrs || null, null);
appendChild(getParentLNode(node), native, viewData);
createDirectivesAndLocals(localRefs);
createDirectivesAndLocals(node, localRefs);
}
/** Mark the end of the <ng-container>. */
@ -784,7 +784,7 @@ export function elementStart(
setUpAttributes(native, attrs);
}
appendChild(getParentLNode(node), native, viewData);
createDirectivesAndLocals(localRefs);
createDirectivesAndLocals(node, localRefs);
}
/**
@ -809,21 +809,27 @@ export function elementCreate(name: string, overriddenRenderer?: Renderer3): REl
return native;
}
function nativeNodeLocalRefExtractor(lNode: LNodeWithLocalRefs): RNode {
return lNode.native;
}
/**
* Creates directive instances and populates local refs.
*
* @param localRefs Local refs of the current node
* @param lNode LNode for which directive and locals should be created
* @param localRefs Local refs of the node in question
* @param localRefExtractor mapping function that extracts local ref value from LNode
*/
function createDirectivesAndLocals(localRefs?: string[] | null) {
const node = previousOrParentNode;
function createDirectivesAndLocals(
lNode: LNodeWithLocalRefs, localRefs: string[] | null | undefined,
localRefExtractor: LocalRefExtractor = nativeNodeLocalRefExtractor) {
if (firstTemplatePass) {
ngDevMode && ngDevMode.firstTemplatePass++;
cacheMatchingDirectivesForNode(node.tNode, tView, localRefs || null);
cacheMatchingDirectivesForNode(lNode.tNode, tView, localRefs || null);
} else {
instantiateDirectivesDirectly();
}
saveResolvedLocalsInData();
saveResolvedLocalsInData(lNode, localRefExtractor);
}
/**
@ -976,12 +982,13 @@ function saveNameToExportMap(
* Takes a list of local names and indices and pushes the resolved local variable values
* to LViewData in the same order as they are loaded in the template with load().
*/
function saveResolvedLocalsInData(): void {
const localNames = previousOrParentNode.tNode.localNames;
function saveResolvedLocalsInData(
lNode: LNodeWithLocalRefs, localRefExtractor: LocalRefExtractor): void {
const localNames = lNode.tNode.localNames;
if (localNames) {
for (let i = 0; i < localNames.length; i += 2) {
const index = localNames[i + 1] as number;
const value = index === -1 ? previousOrParentNode.native : directives ![index];
const value = index === -1 ? localRefExtractor(lNode) : directives ![index];
viewData.push(value);
}
}
@ -1838,10 +1845,13 @@ export function createLContainer(
* @param tagName The name of the container element, if applicable
* @param attrs The attrs attached to the container, if applicable
* @param localRefs A set of local reference bindings on the element.
* @param localRefExtractor A function which extracts local-refs values from the template.
* Defaults to the current element associated with the local-ref.
*/
export function template(
index: number, templateFn: ComponentTemplate<any>| null, tagName?: string | null,
attrs?: TAttributes | null, localRefs?: string[] | null) {
attrs?: TAttributes | null, localRefs?: string[] | null,
localRefExtractor?: LocalRefExtractor) {
// TODO: consider a separate node type for templates
const node = containerInternal(index, tagName || null, attrs || null, localRefs || null);
if (firstTemplatePass) {
@ -1849,7 +1859,7 @@ export function template(
createTView(-1, templateFn, tView.directiveRegistry, tView.pipeRegistry, null);
}
createDirectivesAndLocals(localRefs);
createDirectivesAndLocals(node, localRefs, localRefExtractor);
currentQueries && (currentQueries = currentQueries.addNode(node));
queueLifecycleHooks(node.tNode.flags, tView);
isParent = false;

View File

@ -524,3 +524,16 @@ export type InitialInputs = string[];
// Note: This hack is necessary so we don't erroneously get a circular dependency
// failure based on types.
export const unusedValueExportToPlacateAjd = 1;
/**
* Type representing a set of LNodes that can have local refs (`#foo`) placed on them.
*/
export type LNodeWithLocalRefs = LContainerNode | LElementNode | LElementContainerNode;
/**
* Type for a function that extracts a value for a local refs.
* Example:
* - `<div #nativeDivEl>` - `nativeDivEl` should point to the native `<div>` element;
* - `<ng-template #tplRef>` - `tplRef` should point to the `TemplateRef` instance;
*/
export type LocalRefExtractor = (lNode: LNodeWithLocalRefs) => any;

View File

@ -752,6 +752,9 @@
{
"name": "nativeInsertBefore"
},
{
"name": "nativeNodeLocalRefExtractor"
},
{
"name": "nextContext"
},

View File

@ -8,8 +8,7 @@
import {NgForOfContext} from '@angular/common';
import {getOrCreateNodeInjectorForNode, getOrCreateTemplateRef} from '../../src/render3/di';
import {AttributeMarker, defineComponent} from '../../src/render3/index';
import {AttributeMarker, defineComponent, templateRefExtractor} from '../../src/render3/index';
import {bind, template, elementEnd, elementProperty, elementStart, getCurrentView, interpolation1, interpolation2, interpolation3, interpolationV, listener, load, nextContext, restoreView, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
@ -881,11 +880,11 @@ describe('@angular/common integration', () => {
if (rf1 & RenderFlags.Create) {
text(0, 'from tpl');
}
}, undefined, undefined, ['tpl', '']);
}, undefined, undefined, ['tpl', ''], templateRefExtractor);
template(2, null, null, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']);
}
if (rf & RenderFlags.Update) {
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
const tplRef = load(1);
elementProperty(2, 'ngTemplateOutlet', bind(myApp.showing ? tplRef : null));
}
},

View File

@ -43,4 +43,42 @@ describe('local references', () => {
const fixture = new ComponentFixture(MyComponent);
expect(fixture.html).toEqual(`<input value="World">Hello, World!`);
});
it('should expose TemplateRef when a local ref is placed on ng-template', () => {
type $MyComponent$ = MyComponent;
type $any$ = any;
@Component({
selector: 'my-component',
template: `<ng-template #tpl></ng-template>{{isTemplateRef(tpl)}}`
})
class MyComponent {
isTemplateRef(tplRef: any): boolean { return tplRef.createEmbeddedView != null; }
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
let l1_tpl: any;
if (rf & 1) {
$r3$.ɵtemplate(
0, MyComponent_Template_0, null, null, ['tpl', ''], $r3$.ɵtemplateRefExtractor);
$r3$.ɵtext(2);
}
if (rf & 2) {
l1_tpl = $r3$.ɵreference<any>(1);
$r3$.ɵtextBinding(2, $r3$.ɵinterpolation1('', ctx.isTemplateRef(l1_tpl), ''));
}
function MyComponent_Template_0(rf1: $RenderFlags$, ctx1: $any$) {}
}
});
// NORMATIVE
}
const fixture = new ComponentFixture(MyComponent);
expect(fixture.html).toEqual(`true`);
});
});

View File

@ -10,9 +10,9 @@ import {NgForOfContext} from '@angular/common';
import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core';
import {EventEmitter} from '../..';
import {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, getOrCreateNodeInjectorForNode, getOrCreateTemplateRef} from '../../src/render3/di';
import {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, templateRefExtractor} from '../../src/render3/di';
import {AttributeMarker, QueryList, defineComponent, defineDirective, detectChanges, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective, loadElement, loadQueryList, registerContentQuery, template} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective, loadElement, loadQueryList, reference, registerContentQuery, template} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {query, queryRefresh} from '../../src/render3/query';
@ -1116,25 +1116,25 @@ describe('query', () => {
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind('foo1_' + ctx.idx));
}
}, null, []);
}, null, null, ['tpl1', ''], templateRefExtractor);
element(2, 'div', ['id', 'middle'], ['foo', '']);
element(3, 'div', ['id', 'middle'], ['foo', '']);
template(4, (rf: RenderFlags, ctx: {idx: number}) => {
template(5, (rf: RenderFlags, ctx: {idx: number}) => {
if (rf & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind('foo2_' + ctx.idx));
}
}, null, []);
}, null, null, ['tpl2', ''], templateRefExtractor);
template(5, null, null, [AttributeMarker.SelectOnly, 'vc']);
template(7, null, null, [AttributeMarker.SelectOnly, 'vc']);
}
if (rf & RenderFlags.Update) {
tpl1 = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(1)));
tpl2 = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(4)));
tpl1 = reference(2);
tpl2 = reference(6);
}
},
@ -1219,14 +1219,14 @@ describe('query', () => {
if (rf & RenderFlags.Update) {
elementProperty(0, 'id', bind('foo_' + ctx.container_idx + '_' + ctx.idx));
}
}, null, []);
}, null, [], ['tpl', ''], templateRefExtractor);
template(2, null, null, [AttributeMarker.SelectOnly, 'vc']);
template(3, null, null, [AttributeMarker.SelectOnly, 'vc']);
template(4, null, null, [AttributeMarker.SelectOnly, 'vc']);
}
if (rf & RenderFlags.Update) {
tpl = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(1)));
tpl = reference(2);
}
},
@ -1287,11 +1287,11 @@ describe('query', () => {
if (rf1 & RenderFlags.Create) {
element(0, 'span', ['id', 'from_tpl'], ['foo', '']);
}
}, undefined, undefined, ['tpl', '']);
}, undefined, undefined, ['tpl', ''], templateRefExtractor);
template(3, null, null, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']);
}
if (rf & RenderFlags.Update) {
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(1)));
const tplRef = reference(2);
elementProperty(3, 'ngTemplateOutlet', bind(myApp.show ? tplRef : null));
}
},

View File

@ -7,9 +7,9 @@
*/
import {Component, ComponentFactoryResolver, ElementRef, EmbeddedViewRef, NgModuleRef, Pipe, PipeTransform, RendererFactory2, TemplateRef, ViewContainerRef, createInjector, defineInjector, ɵAPP_ROOT as APP_ROOT, ɵNgModuleDef as NgModuleDef} from '../../src/core';
import {getOrCreateNodeInjectorForNode, getOrCreateTemplateRef} from '../../src/render3/di';
import {templateRefExtractor} from '../../src/render3/di';
import {AttributeMarker, NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectComponentFactoryResolver, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation3, load, loadDirective, nextContext, projection, projectionDef, reserveSlots, template, text, textBinding} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation3, loadDirective, nextContext, projection, projectionDef, reference, reserveSlots, template, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {NgModuleFactory} from '../../src/render3/ng_module_ref';
import {pipe, pipeBind1} from '../../src/render3/pipe';
@ -41,6 +41,9 @@ describe('ViewContainerRef', () => {
}
describe('API', () => {
/**
* {{name}}
*/
function embeddedTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
text(0);
@ -56,28 +59,30 @@ describe('ViewContainerRef', () => {
}
/**
* <ng-template #foo>
* {{name}}
* </ng-template>
* <p vcref="" [tplRef]="foo">
* </p>
* <ng-template #tplRef>{{name}}</ng-template>
* <p vcref [tplRef]="tplRef"></p>
*/
function createTemplate() {
template(0, embeddedTemplate);
element(1, 'p', ['vcref', '']);
template(0, embeddedTemplate, null, null, ['tplRef', ''], templateRefExtractor);
element(2, 'p', ['vcref', '']);
}
function updateTemplate() {
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(1, 'tplRef', bind(tplRef));
const tplRef = reference(1);
elementProperty(2, 'tplRef', bind(tplRef));
}
describe('createEmbeddedView (incl. insert)', () => {
it('should work on elements', () => {
/**
* <ng-template #tplRef>{{name}}</ng-template>
* <header vcref [tplRef]="tplRef"></header>
* <footer></footer>
*/
function createTemplate() {
template(0, embeddedTemplate);
element(1, 'header', ['vcref', '']);
element(2, 'footer');
template(0, embeddedTemplate, null, null, ['tplRef', ''], templateRefExtractor);
element(2, 'header', ['vcref', '']);
element(3, 'footer');
}
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
@ -104,10 +109,15 @@ describe('ViewContainerRef', () => {
const HeaderComponent =
createComponent('header-cmp', function(rf: RenderFlags, ctx: any) {});
/**
* <ng-template #tplRef>{{name}}</ng-template>
* <header-cmp vcref [tplRef]="tplRef"></header-cmp>
* <footer></footer>
*/
function createTemplate() {
template(0, embeddedTemplate);
element(1, 'header-cmp', ['vcref', '']);
element(2, 'footer');
template(0, embeddedTemplate, null, [], ['tplRef', ''], templateRefExtractor);
element(2, 'header-cmp', ['vcref', '']);
element(3, 'footer');
}
const fixture = new TemplateFixture(
@ -135,10 +145,15 @@ describe('ViewContainerRef', () => {
let firstDir: DirectiveWithVCRef;
let secondDir: DirectiveWithVCRef;
/**
* <ng-template #tplRef>{{name}}</ng-template>
* <div vcref [tplRef]="tplRef"></div>
* <div vcref [tplRef]="tplRef"></div>
*/
function createTemplate() {
template(0, embeddedTemplate);
element(1, 'div', ['vcref', '']);
template(0, embeddedTemplate, null, null, ['tplRef', ''], templateRefExtractor);
element(2, 'div', ['vcref', '']);
element(3, 'div', ['vcref', '']);
// for testing only:
firstDir = loadDirective(0);
@ -146,10 +161,9 @@ describe('ViewContainerRef', () => {
}
function update() {
// Hack until we can create local refs to templates
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(1, 'tplRef', bind(tplRef));
const tplRef = reference(1);
elementProperty(2, 'tplRef', bind(tplRef));
elementProperty(3, 'tplRef', bind(tplRef));
}
const fixture = new TemplateFixture(createTemplate, update, [DirectiveWithVCRef]);
@ -162,16 +176,18 @@ describe('ViewContainerRef', () => {
});
it('should work on templates', () => {
/**
* <ng-template vcref #tplRef>{{name}}</ng-template>
* <footer></footer>
*/
function createTemplate() {
template(0, embeddedTemplate, null, ['vcref', '']);
element(1, 'footer');
template(0, embeddedTemplate, null, ['vcref', ''], ['tplRef', ''], templateRefExtractor);
element(2, 'footer');
}
function updateTemplate() {
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
const tplRef = reference(1);
elementProperty(0, 'tplRef', bind(tplRef));
containerRefreshStart(0);
containerRefreshEnd();
}
const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]);
@ -419,18 +435,18 @@ describe('ViewContainerRef', () => {
if (rf & RenderFlags.Update) {
elementProperty(0, 'name', bind(pipeBind1(1, 2, 'C')));
}
});
pipe(1, 'starPipe');
element(2, 'child', ['vcref', '']);
pipe(3, 'starPipe');
element(4, 'child');
}, null, [], ['foo', ''], templateRefExtractor);
pipe(2, 'starPipe');
element(3, 'child', ['vcref', '']);
pipe(4, 'starPipe');
element(5, 'child');
reserveSlots(4);
}
if (rf & RenderFlags.Update) {
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(2, 'tplRef', bind(tplRef));
elementProperty(2, 'name', bind(pipeBind1(1, 2, 'A')));
elementProperty(4, 'name', bind(pipeBind1(1, 4, 'B')));
const tplRef = reference(1);
elementProperty(3, 'tplRef', bind(tplRef));
elementProperty(3, 'name', bind(pipeBind1(2, 2, 'A')));
elementProperty(5, 'name', bind(pipeBind1(4, 4, 'B')));
}
},
directives: [Child, DirectiveWithVCRef],
@ -508,15 +524,13 @@ describe('ViewContainerRef', () => {
*/
const Parent = createComponent('parent', function(rf: RenderFlags, parent: any) {
if (rf & RenderFlags.Create) {
template(0, fooTemplate);
elementStart(1, 'child');
elementEnd();
template(0, fooTemplate, null, null, ['foo', ''], templateRefExtractor);
element(2, 'child');
}
if (rf & RenderFlags.Update) {
// Hack until we have local refs for templates
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(1, 'tpl', bind(tplRef));
const tplRef = reference(1);
elementProperty(2, 'tpl', bind(tplRef));
}
}, [Child]);
@ -599,33 +613,29 @@ describe('ViewContainerRef', () => {
*/
const Parent = createComponent('parent', function(rf: RenderFlags, parent: any) {
if (rf & RenderFlags.Create) {
template(0, rowTemplate);
elementStart(1, 'loop-comp');
elementEnd();
template(0, rowTemplate, null, null, ['rowTemplate', ''], templateRefExtractor);
element(2, 'loop-comp');
}
if (rf & RenderFlags.Update) {
// Hack until we have local refs for templates
const rowTemplateRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(1, 'tpl', bind(rowTemplateRef));
elementProperty(1, 'rows', bind(parent.rows));
const rowTemplateRef = reference(1);
elementProperty(2, 'tpl', bind(rowTemplateRef));
elementProperty(2, 'rows', bind(parent.rows));
}
}, [LoopComp]);
function rowTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(0, cellTemplate);
elementStart(1, 'loop-comp');
elementEnd();
template(0, cellTemplate, null, null, ['cellTemplate', ''], templateRefExtractor);
element(2, 'loop-comp');
}
if (rf & RenderFlags.Update) {
const row = ctx.$implicit as any;
// Hack until we have local refs for templates
const cellTemplateRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(1, 'tpl', bind(cellTemplateRef));
elementProperty(1, 'rows', bind(row.data));
const cellTemplateRef = reference(1);
elementProperty(2, 'tpl', bind(cellTemplateRef));
elementProperty(2, 'rows', bind(row.data));
}
}
@ -1131,18 +1141,20 @@ describe('ViewContainerRef', () => {
factory: () => new Parent(),
template: (rf: RenderFlags, cmp: Parent) => {
if (rf & RenderFlags.Create) {
template(0, embeddedTemplate);
elementStart(1, 'child');
elementStart(2, 'header', ['vcref', '']);
text(3, 'blah');
elementEnd();
template(0, embeddedTemplate, null, null, ['foo', ''], templateRefExtractor);
elementStart(2, 'child');
{
elementStart(3, 'header', ['vcref', '']);
{ text(4, 'blah'); }
elementEnd();
}
elementEnd();
}
let tplRef: any;
if (rf & RenderFlags.Update) {
tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(2, 'tplRef', bind(tplRef));
elementProperty(2, 'name', bind(cmp.name));
tplRef = reference(1);
elementProperty(3, 'tplRef', bind(tplRef));
elementProperty(3, 'name', bind(cmp.name));
}
},
directives: [Child, DirectiveWithVCRef]
@ -1217,19 +1229,19 @@ describe('ViewContainerRef', () => {
factory: () => new Parent(),
template: (rf: RenderFlags, cmp: Parent) => {
if (rf & RenderFlags.Create) {
template(0, embeddedTemplate);
elementStart(1, 'child-with-view');
text(2, 'Before projected');
elementStart(3, 'header', ['vcref', '']);
text(4, 'blah');
template(0, embeddedTemplate, null, undefined, ['foo', ''], templateRefExtractor);
elementStart(2, 'child-with-view');
text(3, 'Before projected');
elementStart(4, 'header', ['vcref', '']);
text(5, 'blah');
elementEnd();
text(5, 'After projected-');
text(6, 'After projected-');
elementEnd();
}
if (rf & RenderFlags.Update) {
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(3, 'tplRef', bind(tplRef));
elementProperty(3, 'name', bind(cmp.name));
const tplRef = reference(1);
elementProperty(4, 'tplRef', bind(tplRef));
elementProperty(4, 'name', bind(cmp.name));
}
},
directives: [ChildWithView, DirectiveWithVCRef]
@ -1294,17 +1306,17 @@ describe('ViewContainerRef', () => {
template: (rf: RenderFlags, cmp: Parent) => {
let tplRef: any;
if (rf & RenderFlags.Create) {
template(0, embeddedTemplate);
elementStart(1, 'child-with-selector');
elementStart(2, 'header', ['vcref', '']);
text(3, 'blah');
template(0, embeddedTemplate, null, null, ['foo', ''], templateRefExtractor);
elementStart(2, 'child-with-selector');
elementStart(3, 'header', ['vcref', '']);
text(4, 'blah');
elementEnd();
elementEnd();
}
if (rf & RenderFlags.Update) {
tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(2, 'tplRef', bind(tplRef));
elementProperty(2, 'name', bind(cmp.name));
tplRef = reference(1);
elementProperty(3, 'tplRef', bind(tplRef));
elementProperty(3, 'name', bind(cmp.name));
}
},
directives: [ChildWithSelector, DirectiveWithVCRef]
@ -1343,17 +1355,17 @@ describe('ViewContainerRef', () => {
template: (rf: RenderFlags, cmp: Parent) => {
let tplRef: any;
if (rf & RenderFlags.Create) {
template(0, embeddedTemplate);
elementStart(1, 'child-with-selector');
elementStart(2, 'footer', ['vcref', '']);
text(3, 'blah');
template(0, embeddedTemplate, null, null, ['foo', ''], templateRefExtractor);
elementStart(2, 'child-with-selector');
elementStart(3, 'footer', ['vcref', '']);
text(4, 'blah');
elementEnd();
elementEnd();
}
if (rf & RenderFlags.Update) {
tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(2, 'tplRef', bind(tplRef));
elementProperty(2, 'name', bind(cmp.name));
tplRef = reference(1);
elementProperty(3, 'tplRef', bind(tplRef));
elementProperty(3, 'name', bind(cmp.name));
}
},
directives: [ChildWithSelector, DirectiveWithVCRef]
@ -1440,15 +1452,15 @@ describe('ViewContainerRef', () => {
if (rf & RenderFlags.Update) {
elementProperty(0, 'name', bind('C'));
}
});
element(1, 'hooks', ['vcref', '']);
element(2, 'hooks');
}, null, [], ['foo', ''], templateRefExtractor);
element(2, 'hooks', ['vcref', '']);
element(3, 'hooks');
}
if (rf & RenderFlags.Update) {
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
elementProperty(1, 'tplRef', bind(tplRef));
elementProperty(1, 'name', bind('A'));
elementProperty(2, 'name', bind('B'));
const tplRef = reference(1);
elementProperty(2, 'tplRef', bind(tplRef));
elementProperty(2, 'name', bind('A'));
elementProperty(3, 'name', bind('B'));
}
},
directives: [ComponentWithHooks, DirectiveWithVCRef]