feat(ivy): add support for local refs on ng-template (#25482)
PR Close #25482
This commit is contained in:
parent
07d8d3994c
commit
31f0f5b3c3
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
|
@ -752,6 +752,9 @@
|
|||
{
|
||||
"name": "nativeInsertBefore"
|
||||
},
|
||||
{
|
||||
"name": "nativeNodeLocalRefExtractor"
|
||||
},
|
||||
{
|
||||
"name": "nextContext"
|
||||
},
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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');
|
||||
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]
|
||||
|
|
Loading…
Reference in New Issue