From 31f0f5b3c371b6e1fd74bb2e15f24234d30f248d Mon Sep 17 00:00:00 2001 From: Pawel Kozlowski Date: Tue, 14 Aug 2018 16:25:01 +0200 Subject: [PATCH] feat(ivy): add support for local refs on ng-template (#25482) PR Close #25482 --- .../core/src/core_render3_private_export.ts | 1 + packages/core/src/render3/di.ts | 10 +- packages/core/src/render3/index.ts | 2 +- packages/core/src/render3/instructions.ts | 40 ++-- packages/core/src/render3/interfaces/node.ts | 13 ++ .../bundling/todo/bundle.golden_symbols.json | 3 + .../test/render3/common_integration_spec.ts | 7 +- .../local_reference_spec.ts | 38 ++++ packages/core/test/render3/query_spec.ts | 28 +-- .../test/render3/view_container_ref_spec.ts | 200 ++++++++++-------- 10 files changed, 213 insertions(+), 129 deletions(-) diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index 8bb2cb5c2c..d5936a8dfc 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -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, diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index 13d550cadb..f59afc3726 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -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 implements viewEngine_TemplateRef { return viewRef; } } + +/** + * Retrieves `TemplateRef` instance from `Injector` when a local reference is placed on the + * `` element. + */ +export function templateRefExtractor(lNode: LNodeWithLocalRefs) { + return getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(lNode)); +} \ No newline at end of file diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index 5b4e068c57..3b268aa97e 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -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'; diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index d8759c0101..5c49f08dd8 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -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 . */ @@ -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| 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; diff --git a/packages/core/src/render3/interfaces/node.ts b/packages/core/src/render3/interfaces/node.ts index 3d6682a0a5..bea7adca1e 100644 --- a/packages/core/src/render3/interfaces/node.ts +++ b/packages/core/src/render3/interfaces/node.ts @@ -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: + * - `
` - `nativeDivEl` should point to the native `
` element; + * - `` - `tplRef` should point to the `TemplateRef` instance; + */ +export type LocalRefExtractor = (lNode: LNodeWithLocalRefs) => any; \ No newline at end of file diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 2ebf4e57eb..12ba180c9c 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -752,6 +752,9 @@ { "name": "nativeInsertBefore" }, + { + "name": "nativeNodeLocalRefExtractor" + }, { "name": "nextContext" }, diff --git a/packages/core/test/render3/common_integration_spec.ts b/packages/core/test/render3/common_integration_spec.ts index a8238528a9..c91a51e38d 100644 --- a/packages/core/test/render3/common_integration_spec.ts +++ b/packages/core/test/render3/common_integration_spec.ts @@ -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)); } }, diff --git a/packages/core/test/render3/compiler_canonical/local_reference_spec.ts b/packages/core/test/render3/compiler_canonical/local_reference_spec.ts index ce0bf7484c..db20cb1001 100644 --- a/packages/core/test/render3/compiler_canonical/local_reference_spec.ts +++ b/packages/core/test/render3/compiler_canonical/local_reference_spec.ts @@ -43,4 +43,42 @@ describe('local references', () => { const fixture = new ComponentFixture(MyComponent); expect(fixture.html).toEqual(`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: `{{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(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`); + }); }); diff --git a/packages/core/test/render3/query_spec.ts b/packages/core/test/render3/query_spec.ts index 2a9c16c042..aff63ad407 100644 --- a/packages/core/test/render3/query_spec.ts +++ b/packages/core/test/render3/query_spec.ts @@ -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)); } }, diff --git a/packages/core/test/render3/view_container_ref_spec.ts b/packages/core/test/render3/view_container_ref_spec.ts index 53459de42d..f9af7da7f7 100644 --- a/packages/core/test/render3/view_container_ref_spec.ts +++ b/packages/core/test/render3/view_container_ref_spec.ts @@ -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', () => { } /** - * - * {{name}} - * - *

- *

+ * {{name}} + *

*/ 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', () => { + /** + * {{name}} + *
+ *
+ */ 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) {}); + /** + * {{name}} + * + *
+ */ 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; + /** + * {{name}} + *
+ *
+ */ 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', () => { + /** + * {{name}} + * + */ 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]