refactor(ivy): special injection tokens should not be cached (#26048)
PR Close #26048
This commit is contained in:
parent
64aa6701f6
commit
d5f47d6b71
|
@ -14,7 +14,7 @@ import {Sanitizer} from '../sanitization/security';
|
|||
|
||||
import {assertComponentType, assertDefined} from './assert';
|
||||
import {queueInitHooks, queueLifecycleHooks} from './hooks';
|
||||
import {CLEAN_PROMISE, baseDirectiveCreate, createLViewData, createTView, detectChangesInternal, enterView, executeInitAndContentHooks, getRootView, hostElement, initChangeDetectorIfExisting, leaveView, locateHostElement, setHostBindings, queueHostBindingForCheck,} from './instructions';
|
||||
import {CLEAN_PROMISE, baseDirectiveCreate, createLViewData, createTView, detectChangesInternal, enterView, executeInitAndContentHooks, getRootView, hostElement, leaveView, locateHostElement, setHostBindings, queueHostBindingForCheck,} from './instructions';
|
||||
import {ComponentDef, ComponentDefInternal, ComponentType} from './interfaces/definition';
|
||||
import {LElementNode} from './interfaces/node';
|
||||
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||
|
@ -150,7 +150,6 @@ export function createRootComponent<T>(
|
|||
if (componentDef.hostBindings) queueHostBindingForCheck(0, componentDef.hostVars);
|
||||
rootContext.components.push(component);
|
||||
(elementNode.data as LViewData)[CONTEXT] = component;
|
||||
initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data as LViewData);
|
||||
|
||||
hostFeatures && hostFeatures.forEach((feature) => feature(component, componentDef));
|
||||
setHostBindings(rootView[TVIEW].hostBindings);
|
||||
|
|
|
@ -145,10 +145,6 @@ export function getOrCreateNodeInjectorForNode(
|
|||
cbf5: parentInjector == null ? 0 : parentInjector.cbf5 | parentInjector.bf5,
|
||||
cbf6: parentInjector == null ? 0 : parentInjector.cbf6 | parentInjector.bf6,
|
||||
cbf7: parentInjector == null ? 0 : parentInjector.cbf7 | parentInjector.bf7,
|
||||
templateRef: null,
|
||||
viewContainerRef: null,
|
||||
elementRef: null,
|
||||
changeDetectorRef: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -207,7 +203,7 @@ export function directiveInject<T>(
|
|||
* @returns The ElementRef instance to use
|
||||
*/
|
||||
export function injectElementRef(): viewEngine_ElementRef {
|
||||
return getOrCreateElementRef(getOrCreateNodeInjector());
|
||||
return createElementRef(getPreviousOrParentTNode(), _getViewData());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -217,7 +213,7 @@ export function injectElementRef(): viewEngine_ElementRef {
|
|||
* @returns The TemplateRef instance to use
|
||||
*/
|
||||
export function injectTemplateRef<T>(): viewEngine_TemplateRef<T> {
|
||||
return getOrCreateTemplateRef<T>(getOrCreateNodeInjector());
|
||||
return createTemplateRef<T>(getPreviousOrParentTNode(), _getViewData());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -227,12 +223,14 @@ export function injectTemplateRef<T>(): viewEngine_TemplateRef<T> {
|
|||
* @returns The ViewContainerRef instance to use
|
||||
*/
|
||||
export function injectViewContainerRef(): viewEngine_ViewContainerRef {
|
||||
return getOrCreateContainerRef(getOrCreateNodeInjector());
|
||||
const previousTNode =
|
||||
getPreviousOrParentTNode() as TElementNode | TElementContainerNode | TContainerNode;
|
||||
return createContainerRef(previousTNode, _getViewData());
|
||||
}
|
||||
|
||||
/** Returns a ChangeDetectorRef (a.k.a. a ViewRef) */
|
||||
export function injectChangeDetectorRef(): viewEngine_ChangeDetectorRef {
|
||||
return getOrCreateChangeDetectorRef(getOrCreateNodeInjector(), null);
|
||||
return createViewRef(getPreviousOrParentTNode(), _getViewData(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -302,34 +300,25 @@ export function injectAttribute(attrNameToInject: string): string|undefined {
|
|||
|
||||
/**
|
||||
* Creates a ViewRef and stores it on the injector as ChangeDetectorRef (public alias).
|
||||
* Or, if it already exists, retrieves the existing instance.
|
||||
*
|
||||
* @param hostTNode The node that is requesting a ChangeDetectorRef
|
||||
* @param hostView The view to which the node belongs
|
||||
* @param context The context for this change detector ref
|
||||
* @returns The ChangeDetectorRef to use
|
||||
*/
|
||||
export function getOrCreateChangeDetectorRef(
|
||||
di: LInjector, context: any): viewEngine_ChangeDetectorRef {
|
||||
if (di.changeDetectorRef) return di.changeDetectorRef;
|
||||
|
||||
const currentTNode = di.tNode;
|
||||
if (isComponent(currentTNode)) {
|
||||
return di.changeDetectorRef =
|
||||
new ViewRef(getLNode(currentTNode, di.view).data as LViewData, context);
|
||||
} else if (currentTNode.type === TNodeType.Element) {
|
||||
return di.changeDetectorRef = getOrCreateHostChangeDetector(di.view);
|
||||
export function createViewRef(
|
||||
hostTNode: TNode, hostView: LViewData, context: any): viewEngine_ChangeDetectorRef {
|
||||
if (isComponent(hostTNode)) {
|
||||
const componentIndex = hostTNode.flags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||
const componentView = getLNode(hostTNode, hostView).data as LViewData;
|
||||
return new ViewRef(componentView, context, componentIndex);
|
||||
} else if (hostTNode.type === TNodeType.Element) {
|
||||
const hostComponentView = findComponentView(hostView);
|
||||
return new ViewRef(hostComponentView, hostComponentView[CONTEXT], -1);
|
||||
}
|
||||
return null !;
|
||||
}
|
||||
|
||||
/** Gets or creates ChangeDetectorRef for the closest host component */
|
||||
function getOrCreateHostChangeDetector(currentView: LViewData): viewEngine_ChangeDetectorRef {
|
||||
const hostComponentView = findComponentView(currentView);
|
||||
const hostNode = getHostElementNode(hostComponentView) !;
|
||||
const hostInjector = hostNode.nodeInjector;
|
||||
const existingRef = hostInjector && hostInjector.changeDetectorRef;
|
||||
|
||||
return existingRef ? existingRef : new ViewRef(hostComponentView, hostComponentView[CONTEXT]);
|
||||
}
|
||||
|
||||
function getOrCreateRenderer2(di: LInjector): Renderer2 {
|
||||
const renderer = di.view[RENDERER];
|
||||
if (isProceduralRenderer(renderer)) {
|
||||
|
@ -537,44 +526,44 @@ function sameHostView(injector: LInjector): boolean {
|
|||
}
|
||||
|
||||
export class ReadFromInjectorFn<T> {
|
||||
constructor(readonly read: (injector: LInjector, tNode: TNode, directiveIndex?: number) => T) {}
|
||||
constructor(readonly read: (tNode: TNode, view: LViewData, directiveIndex?: number) => T) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ElementRef for a given node injector and stores it on the injector.
|
||||
* Or, if the ElementRef already exists, retrieves the existing ElementRef.
|
||||
*
|
||||
* @param di The node injector where we should store a created ElementRef
|
||||
* @returns The ElementRef instance to use
|
||||
*/
|
||||
export function getOrCreateElementRef(di: LInjector): viewEngine_ElementRef {
|
||||
return di.elementRef || (di.elementRef = new ElementRef(getLNode(di.tNode, di.view).native));
|
||||
export function createElementRef(tNode: TNode, view: LViewData): viewEngine_ElementRef {
|
||||
return new ElementRef(getLNode(tNode, view).native);
|
||||
}
|
||||
|
||||
export const QUERY_READ_TEMPLATE_REF = <QueryReadType<viewEngine_TemplateRef<any>>>(
|
||||
new ReadFromInjectorFn<viewEngine_TemplateRef<any>>(
|
||||
(injector: LInjector) => getOrCreateTemplateRef(injector)) as any);
|
||||
(tNode: TNode, view: LViewData) => { return createTemplateRef(tNode, view);}) as any);
|
||||
|
||||
export const QUERY_READ_CONTAINER_REF = <QueryReadType<viewEngine_ViewContainerRef>>(
|
||||
new ReadFromInjectorFn<viewEngine_ViewContainerRef>(
|
||||
(injector: LInjector) => getOrCreateContainerRef(injector)) as any);
|
||||
(tNode: TNode, view: LViewData) => createContainerRef(
|
||||
tNode as TElementNode | TContainerNode | TElementContainerNode, view)) as any);
|
||||
|
||||
export const QUERY_READ_ELEMENT_REF =
|
||||
<QueryReadType<viewEngine_ElementRef>>(new ReadFromInjectorFn<viewEngine_ElementRef>(
|
||||
(injector: LInjector) => getOrCreateElementRef(injector)) as any);
|
||||
(tNode: TNode, view: LViewData) => createElementRef(tNode, view)) as any);
|
||||
|
||||
export const QUERY_READ_FROM_NODE =
|
||||
(new ReadFromInjectorFn<any>((injector: LInjector, tNode: TNode, directiveIdx: number) => {
|
||||
(new ReadFromInjectorFn<any>((tNode: TNode, view: LViewData, directiveIdx: number) => {
|
||||
ngDevMode && assertNodeOfPossibleTypes(
|
||||
tNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
|
||||
if (directiveIdx > -1) {
|
||||
return injector.view[DIRECTIVES] ![directiveIdx];
|
||||
return view[DIRECTIVES] ![directiveIdx];
|
||||
}
|
||||
if (tNode.type === TNodeType.Element || tNode.type === TNodeType.ElementContainer) {
|
||||
return getOrCreateElementRef(injector);
|
||||
return createElementRef(tNode, view);
|
||||
}
|
||||
if (tNode.type === TNodeType.Container) {
|
||||
return getOrCreateTemplateRef(injector);
|
||||
return createTemplateRef(tNode, view);
|
||||
}
|
||||
if (ngDevMode) {
|
||||
// should never happen
|
||||
|
@ -586,42 +575,38 @@ export const QUERY_READ_FROM_NODE =
|
|||
class ElementRef extends viewEngine_ElementRef {}
|
||||
|
||||
/**
|
||||
* Creates a ViewContainerRef and stores it on the injector. Or, if the ViewContainerRef
|
||||
* already exists, retrieves the existing ViewContainerRef.
|
||||
* Creates a ViewContainerRef and stores it on the injector.
|
||||
*
|
||||
* @param hostTNode The node that is requesting a ViewContainerRef
|
||||
* @param hostView The view to which the node belongs
|
||||
* @returns The ViewContainerRef instance to use
|
||||
*/
|
||||
export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainerRef {
|
||||
if (!di.viewContainerRef) {
|
||||
const hostLNode =
|
||||
getPreviousOrParentNode() as LElementNode | LContainerNode | LElementContainerNode;
|
||||
const hostTNode = getPreviousOrParentTNode() as TElementNode | TContainerNode;
|
||||
ngDevMode && assertNodeOfPossibleTypes(
|
||||
hostTNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
|
||||
export function createContainerRef(
|
||||
hostTNode: TElementNode | TContainerNode | TElementContainerNode,
|
||||
hostView: LViewData): viewEngine_ViewContainerRef {
|
||||
const hostLNode = getLNode(hostTNode, hostView);
|
||||
ngDevMode && assertNodeOfPossibleTypes(
|
||||
hostTNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
|
||||
|
||||
const hostView = di.view;
|
||||
const lContainer = createLContainer(hostView, true);
|
||||
const comment = hostView[RENDERER].createComment(ngDevMode ? 'container' : '');
|
||||
const lContainerNode: LContainerNode =
|
||||
createLNodeObject(TNodeType.Container, hostLNode.nodeInjector, comment, lContainer);
|
||||
const lContainer = createLContainer(hostView, true);
|
||||
const comment = hostView[RENDERER].createComment(ngDevMode ? 'container' : '');
|
||||
const lContainerNode: LContainerNode =
|
||||
createLNodeObject(TNodeType.Container, hostLNode.nodeInjector, comment, lContainer);
|
||||
|
||||
lContainer[RENDER_PARENT] = getRenderParent(hostTNode, hostView);
|
||||
lContainer[RENDER_PARENT] = getRenderParent(hostTNode, hostView);
|
||||
|
||||
appendChild(comment, hostTNode, hostView);
|
||||
appendChild(comment, hostTNode, hostView);
|
||||
|
||||
if (!hostTNode.dynamicContainerNode) {
|
||||
hostTNode.dynamicContainerNode =
|
||||
createTNode(TNodeType.Container, -1, null, null, hostTNode, null);
|
||||
}
|
||||
|
||||
hostLNode.dynamicLContainerNode = lContainerNode;
|
||||
addToViewTree(hostView, hostTNode.index as number, lContainer);
|
||||
|
||||
di.viewContainerRef = new ViewContainerRef(
|
||||
lContainer, hostTNode.dynamicContainerNode as TContainerNode, hostTNode, hostView);
|
||||
if (!hostTNode.dynamicContainerNode) {
|
||||
hostTNode.dynamicContainerNode =
|
||||
createTNode(TNodeType.Container, -1, null, null, hostTNode, null);
|
||||
}
|
||||
|
||||
return di.viewContainerRef;
|
||||
hostLNode.dynamicLContainerNode = lContainerNode;
|
||||
addToViewTree(hostView, hostTNode.index as number, lContainer);
|
||||
|
||||
return new ViewContainerRef(
|
||||
lContainer, hostTNode.dynamicContainerNode as TContainerNode, hostTNode, hostView);
|
||||
}
|
||||
|
||||
export class NodeInjector implements Injector {
|
||||
|
@ -629,16 +614,16 @@ export class NodeInjector implements Injector {
|
|||
|
||||
get(token: any): any {
|
||||
if (token === viewEngine_TemplateRef) {
|
||||
return getOrCreateTemplateRef(this._lInjector);
|
||||
return createTemplateRef(this._lInjector.tNode, this._lInjector.view);
|
||||
}
|
||||
if (token === viewEngine_ViewContainerRef) {
|
||||
return getOrCreateContainerRef(this._lInjector);
|
||||
return createContainerRef(this._lInjector.tNode, this._lInjector.view);
|
||||
}
|
||||
if (token === viewEngine_ElementRef) {
|
||||
return getOrCreateElementRef(this._lInjector);
|
||||
return createElementRef(this._lInjector.tNode, this._lInjector.view);
|
||||
}
|
||||
if (token === viewEngine_ChangeDetectorRef) {
|
||||
return getOrCreateChangeDetectorRef(this._lInjector, null);
|
||||
return createViewRef(this._lInjector.tNode, this._lInjector.view, null);
|
||||
}
|
||||
if (token === Renderer2) {
|
||||
return getOrCreateRenderer2(this._lInjector);
|
||||
|
@ -666,7 +651,7 @@ class ViewContainerRef extends viewEngine_ViewContainerRef {
|
|||
// TODO: Remove LNode lookup when removing LNode.nodeInjector
|
||||
const injector =
|
||||
getOrCreateNodeInjectorForNode(this._getHostNode(), this._hostTNode, this._hostView);
|
||||
return getOrCreateElementRef(injector);
|
||||
return createElementRef(injector.tNode, injector.view);
|
||||
}
|
||||
|
||||
get injector(): Injector {
|
||||
|
@ -776,23 +761,20 @@ class ViewContainerRef extends viewEngine_ViewContainerRef {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a TemplateRef and stores it on the injector. Or, if the TemplateRef already
|
||||
* exists, retrieves the existing TemplateRef.
|
||||
* Creates a TemplateRef and stores it on the injector.
|
||||
*
|
||||
* @param di The node injector where we should store a created TemplateRef
|
||||
* @param hostTNode The node that is requesting a TemplateRef
|
||||
* @param hostView The view to which the node belongs
|
||||
* @returns The TemplateRef instance to use
|
||||
*/
|
||||
export function getOrCreateTemplateRef<T>(di: LInjector): viewEngine_TemplateRef<T> {
|
||||
if (!di.templateRef) {
|
||||
const hostNode = getPreviousOrParentNode() as LContainerNode;
|
||||
const hostTNode = getPreviousOrParentTNode() as TContainerNode;
|
||||
ngDevMode && assertNodeType(hostTNode, TNodeType.Container);
|
||||
ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated');
|
||||
di.templateRef = new TemplateRef<any>(
|
||||
di.view, getOrCreateElementRef(di), hostTNode.tViews as TView, getRenderer(),
|
||||
hostNode.data ![QUERIES]);
|
||||
}
|
||||
return di.templateRef;
|
||||
export function createTemplateRef<T>(
|
||||
hostTNode: TNode, hostView: LViewData): viewEngine_TemplateRef<T> {
|
||||
const hostNode = getLNode(hostTNode, hostView);
|
||||
ngDevMode && assertNodeType(hostTNode, TNodeType.Container);
|
||||
ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated');
|
||||
return new TemplateRef<any>(
|
||||
hostView, createElementRef(hostTNode, hostView), hostTNode.tViews as TView, getRenderer(),
|
||||
hostNode.data ![QUERIES]);
|
||||
}
|
||||
|
||||
export function getFactoryOf<T>(type: Type<any>): ((type?: Type<T>) => T)|null {
|
||||
|
@ -835,7 +817,7 @@ class TemplateRef<T> extends viewEngine_TemplateRef<T> {
|
|||
insertView(lView, container, hostView !, index !, tContainerNode !.parent !.index);
|
||||
}
|
||||
renderEmbeddedTemplate(lView, this._tView, context, RenderFlags.Create);
|
||||
const viewRef = new ViewRef(lView, context);
|
||||
const viewRef = new ViewRef(lView, context, -1);
|
||||
viewRef._tViewNode = lView[HOST_NODE] as TViewNode;
|
||||
return viewRef;
|
||||
}
|
||||
|
@ -846,7 +828,5 @@ class TemplateRef<T> extends viewEngine_TemplateRef<T> {
|
|||
* `<ng-template>` element.
|
||||
*/
|
||||
export function templateRefExtractor(tNode: TContainerNode, currentView: LViewData) {
|
||||
// TODO: remove this lookup with removing LNode.nodeInjector
|
||||
const lNode = getLNode(tNode, currentView) as LContainerNode;
|
||||
return getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(lNode, tNode, currentView));
|
||||
return createTemplateRef(tNode, currentView);
|
||||
}
|
||||
|
|
|
@ -899,12 +899,18 @@ function findDirectiveMatches(tNode: TNode): CurrentMatchesList|null {
|
|||
for (let i = 0; i < registry.length; i++) {
|
||||
const def = registry[i];
|
||||
if (isNodeMatchingSelectorList(tNode, def.selectors !)) {
|
||||
matches || (matches = []);
|
||||
if ((def as ComponentDefInternal<any>).template) {
|
||||
if (tNode.flags & TNodeFlags.isComponent) throwMultipleComponentError(tNode);
|
||||
addComponentLogic(def as ComponentDefInternal<any>);
|
||||
tNode.flags = TNodeFlags.isComponent;
|
||||
|
||||
// The component is always stored first with directives after.
|
||||
matches.unshift(def, null);
|
||||
} else {
|
||||
matches.push(def, null);
|
||||
}
|
||||
if (def.diPublic) def.diPublic(def);
|
||||
(matches || (matches = [])).push(def, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -948,14 +954,6 @@ export function queueHostBindingForCheck(dirIndex: number, hostVars: number): vo
|
|||
])).push(dirIndex, previousOrParentTNode.index - HEADER_OFFSET);
|
||||
}
|
||||
|
||||
/** Sets the context for a ChangeDetectorRef to the given instance. */
|
||||
export function initChangeDetectorIfExisting(
|
||||
injector: LInjector | null, instance: any, view: LViewData): void {
|
||||
if (injector && injector.changeDetectorRef != null) {
|
||||
(injector.changeDetectorRef as ViewRef<any>)._setComponentContext(view, instance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function instantiates the given directives.
|
||||
*/
|
||||
|
@ -976,6 +974,12 @@ function instantiateDirectivesDirectly() {
|
|||
|
||||
for (let i = start; i < end; i++) {
|
||||
const def: DirectiveDefInternal<any> = tDirectives[i];
|
||||
|
||||
// Component view must be set on node before the factory is created so
|
||||
// ChangeDetectorRefs have a way to store component view on creation.
|
||||
if ((def as ComponentDefInternal<any>).template) {
|
||||
addComponentLogic(def as ComponentDefInternal<any>);
|
||||
}
|
||||
directiveCreate(i, def.factory(), def);
|
||||
}
|
||||
}
|
||||
|
@ -1698,13 +1702,11 @@ export function textBinding<T>(index: number, value: T | NO_CHANGE): void {
|
|||
export function directiveCreate<T>(
|
||||
directiveDefIdx: number, directive: T,
|
||||
directiveDef: DirectiveDefInternal<T>| ComponentDefInternal<T>): T {
|
||||
const hostNode = getPreviousOrParentNode() !;
|
||||
const hostNode = getLNode(previousOrParentTNode, viewData);
|
||||
const instance = baseDirectiveCreate(directiveDefIdx, directive, directiveDef, hostNode);
|
||||
|
||||
const isComponent = (directiveDef as ComponentDefInternal<T>).template;
|
||||
if (isComponent) {
|
||||
addComponentLogic(
|
||||
directiveDefIdx, directive, directiveDef as ComponentDefInternal<T>, hostNode);
|
||||
if ((directiveDef as ComponentDefInternal<T>).template) {
|
||||
hostNode.data ![CONTEXT] = directive;
|
||||
}
|
||||
|
||||
if (firstTemplatePass) {
|
||||
|
@ -1727,8 +1729,9 @@ export function directiveCreate<T>(
|
|||
return instance;
|
||||
}
|
||||
|
||||
function addComponentLogic<T>(
|
||||
directiveIndex: number, instance: T, def: ComponentDefInternal<T>, hostNode: LNode): void {
|
||||
function addComponentLogic<T>(def: ComponentDefInternal<T>): void {
|
||||
const hostNode = getLNode(previousOrParentTNode, viewData);
|
||||
|
||||
const tView = getOrCreateTView(
|
||||
def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery);
|
||||
|
||||
|
@ -1737,15 +1740,13 @@ function addComponentLogic<T>(
|
|||
const componentView = addToViewTree(
|
||||
viewData, previousOrParentTNode.index as number,
|
||||
createLViewData(
|
||||
rendererFactory.createRenderer(hostNode.native as RElement, def), tView, instance,
|
||||
rendererFactory.createRenderer(hostNode.native as RElement, def), tView, null,
|
||||
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, getCurrentSanitizer()));
|
||||
|
||||
// We need to set the host node/data here because when the component LNode was created,
|
||||
// we didn't yet know it was a component (just an element).
|
||||
(hostNode as{data: LViewData}).data = componentView;
|
||||
(componentView as LViewData)[HOST_NODE] = getPreviousOrParentTNode() as TElementNode;
|
||||
|
||||
initChangeDetectorIfExisting(hostNode.nodeInjector, instance, componentView);
|
||||
(componentView as LViewData)[HOST_NODE] = previousOrParentTNode as TElementNode;
|
||||
|
||||
if (firstTemplatePass) queueComponentIndexForCheck();
|
||||
}
|
||||
|
|
|
@ -70,22 +70,6 @@ export interface LInjector {
|
|||
cbf5: number;
|
||||
cbf6: number;
|
||||
cbf7: number;
|
||||
|
||||
/** Stores the TemplateRef so subsequent injections of the TemplateRef get the same instance. */
|
||||
templateRef: TemplateRef<any>|null;
|
||||
|
||||
/** Stores the ViewContainerRef so subsequent injections of the ViewContainerRef get the same
|
||||
* instance. */
|
||||
viewContainerRef: ViewContainerRef|null;
|
||||
|
||||
/** Stores the ElementRef so subsequent injections of the ElementRef get the same instance. */
|
||||
elementRef: ElementRef|null;
|
||||
|
||||
/**
|
||||
* Stores the ChangeDetectorRef so subsequent injections of the ChangeDetectorRef get the
|
||||
* same instance.
|
||||
*/
|
||||
changeDetectorRef: ChangeDetectorRef|null;
|
||||
}
|
||||
|
||||
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
||||
|
|
|
@ -265,10 +265,10 @@ function getIdxOfMatchingDirective(tNode: TNode, currentView: LViewData, type: T
|
|||
}
|
||||
|
||||
function readFromNodeInjector(
|
||||
nodeInjector: LInjector, tNode: TNode, currentView: LViewData,
|
||||
read: QueryReadType<any>| Type<any>, directiveIdx: number): any {
|
||||
tNode: TNode, currentView: LViewData, read: QueryReadType<any>| Type<any>,
|
||||
directiveIdx: number): any {
|
||||
if (read instanceof ReadFromInjectorFn) {
|
||||
return read.read(nodeInjector, tNode, directiveIdx);
|
||||
return read.read(tNode, currentView, directiveIdx);
|
||||
} else {
|
||||
const matchingIdx = getIdxOfMatchingDirective(tNode, currentView, read as Type<any>);
|
||||
if (matchingIdx !== null) {
|
||||
|
@ -282,10 +282,6 @@ function add(
|
|||
query: LQuery<any>| null, tNode: TElementNode | TContainerNode | TElementContainerNode) {
|
||||
const currentView = _getViewData();
|
||||
|
||||
// TODO: remove this lookup when nodeInjector is removed from LNode
|
||||
const nodeInjector =
|
||||
getOrCreateNodeInjectorForNode(getLNode(tNode, currentView), tNode, currentView);
|
||||
|
||||
while (query) {
|
||||
const predicate = query.predicate;
|
||||
const type = predicate.type;
|
||||
|
@ -294,8 +290,8 @@ function add(
|
|||
if (directiveIdx !== null) {
|
||||
// a node is matching a predicate - determine what to read
|
||||
// if read token and / or strategy is not specified, use type as read token
|
||||
const result = readFromNodeInjector(
|
||||
nodeInjector, tNode, currentView, predicate.read || type, directiveIdx);
|
||||
const result =
|
||||
readFromNodeInjector(tNode, currentView, predicate.read || type, directiveIdx);
|
||||
if (result !== null) {
|
||||
addMatch(query, result);
|
||||
}
|
||||
|
@ -308,8 +304,7 @@ function add(
|
|||
// a node is matching a predicate - determine what to read
|
||||
// note that queries using name selector must specify read strategy
|
||||
ngDevMode && assertDefined(predicate.read, 'the node should have a predicate');
|
||||
const result = readFromNodeInjector(
|
||||
nodeInjector, tNode, currentView, predicate.read !, directiveIdx);
|
||||
const result = readFromNodeInjector(tNode, currentView, predicate.read !, directiveIdx);
|
||||
if (result !== null) {
|
||||
addMatch(query, result);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEn
|
|||
|
||||
import {checkNoChanges, checkNoChangesInRootView, detectChanges, detectChangesInRootView, getRendererFactory, markViewDirty, storeCleanupFn, viewAttached} from './instructions';
|
||||
import {TViewNode} from './interfaces/node';
|
||||
import {FLAGS, LViewData, LViewFlags} from './interfaces/view';
|
||||
import {DIRECTIVES, FLAGS, LViewData, LViewFlags, PARENT} from './interfaces/view';
|
||||
import {destroyLView} from './node_manipulation';
|
||||
|
||||
|
||||
|
@ -37,20 +37,14 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int
|
|||
*/
|
||||
_tViewNode: TViewNode|null = null;
|
||||
|
||||
context: T;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
rootNodes !: any[];
|
||||
|
||||
constructor(_view: LViewData, context: T|null) {
|
||||
this.context = context !;
|
||||
constructor(_view: LViewData, private _context: T|null, private _componentIndex: number) {
|
||||
this._view = _view;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_setComponentContext(view: LViewData, context: T) {
|
||||
this._view = view;
|
||||
this.context = context;
|
||||
}
|
||||
get context(): T { return this._context ? this._context : this._lookUpContext(); }
|
||||
|
||||
get destroyed(): boolean {
|
||||
return (this._view[FLAGS] & LViewFlags.Destroyed) === LViewFlags.Destroyed;
|
||||
|
@ -260,11 +254,15 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int
|
|||
detachFromAppRef() { this._appRef = null; }
|
||||
|
||||
attachToAppRef(appRef: ApplicationRef) { this._appRef = appRef; }
|
||||
|
||||
private _lookUpContext(): T {
|
||||
return this._context = this._view[PARENT] ![DIRECTIVES] ![this._componentIndex] as T;
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export class RootViewRef<T> extends ViewRef<T> {
|
||||
constructor(public _view: LViewData) { super(_view, null); }
|
||||
constructor(public _view: LViewData) { super(_view, null, -1); }
|
||||
|
||||
detectChanges(): void { detectChangesInRootView(this._view); }
|
||||
|
||||
|
|
|
@ -266,9 +266,6 @@
|
|||
{
|
||||
"name": "hostElement"
|
||||
},
|
||||
{
|
||||
"name": "initChangeDetectorIfExisting"
|
||||
},
|
||||
{
|
||||
"name": "invertObject"
|
||||
},
|
||||
|
|
|
@ -404,9 +404,15 @@
|
|||
{
|
||||
"name": "contextViewData"
|
||||
},
|
||||
{
|
||||
"name": "createContainerRef"
|
||||
},
|
||||
{
|
||||
"name": "createDirectivesAndLocals"
|
||||
},
|
||||
{
|
||||
"name": "createElementRef"
|
||||
},
|
||||
{
|
||||
"name": "createEmbeddedViewAndNode"
|
||||
},
|
||||
|
@ -443,6 +449,9 @@
|
|||
{
|
||||
"name": "createTView"
|
||||
},
|
||||
{
|
||||
"name": "createTemplateRef"
|
||||
},
|
||||
{
|
||||
"name": "createTextNode"
|
||||
},
|
||||
|
@ -452,6 +461,9 @@
|
|||
{
|
||||
"name": "createViewQuery"
|
||||
},
|
||||
{
|
||||
"name": "createViewRef"
|
||||
},
|
||||
{
|
||||
"name": "defineComponent"
|
||||
},
|
||||
|
@ -620,18 +632,6 @@
|
|||
{
|
||||
"name": "getMultiStartIndex"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateChangeDetectorRef"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateContainerRef"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateElementRef"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateHostChangeDetector"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateInjectable"
|
||||
},
|
||||
|
@ -647,9 +647,6 @@
|
|||
{
|
||||
"name": "getOrCreateTView"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateTemplateRef"
|
||||
},
|
||||
{
|
||||
"name": "getParentLNode"
|
||||
},
|
||||
|
@ -719,9 +716,6 @@
|
|||
{
|
||||
"name": "hostElement"
|
||||
},
|
||||
{
|
||||
"name": "initChangeDetectorIfExisting"
|
||||
},
|
||||
{
|
||||
"name": "inject"
|
||||
},
|
||||
|
|
|
@ -1274,9 +1274,15 @@
|
|||
{
|
||||
"name": "couldBeInjectableType"
|
||||
},
|
||||
{
|
||||
"name": "createContainerRef"
|
||||
},
|
||||
{
|
||||
"name": "createDirectivesAndLocals"
|
||||
},
|
||||
{
|
||||
"name": "createElementRef"
|
||||
},
|
||||
{
|
||||
"name": "createEmbeddedViewAndNode"
|
||||
},
|
||||
|
@ -1325,6 +1331,9 @@
|
|||
{
|
||||
"name": "createTView"
|
||||
},
|
||||
{
|
||||
"name": "createTemplateRef"
|
||||
},
|
||||
{
|
||||
"name": "createTextNode"
|
||||
},
|
||||
|
@ -1334,6 +1343,9 @@
|
|||
{
|
||||
"name": "createViewQuery"
|
||||
},
|
||||
{
|
||||
"name": "createViewRef"
|
||||
},
|
||||
{
|
||||
"name": "dateGetter"
|
||||
},
|
||||
|
@ -1706,18 +1718,6 @@
|
|||
{
|
||||
"name": "getNumberOfCurrencyDigits"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateChangeDetectorRef"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateContainerRef"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateElementRef"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateHostChangeDetector"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateInjectable"
|
||||
},
|
||||
|
@ -1733,9 +1733,6 @@
|
|||
{
|
||||
"name": "getOrCreateTView"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateTemplateRef"
|
||||
},
|
||||
{
|
||||
"name": "getOriginalError"
|
||||
},
|
||||
|
@ -1844,9 +1841,6 @@
|
|||
{
|
||||
"name": "identity"
|
||||
},
|
||||
{
|
||||
"name": "initChangeDetectorIfExisting"
|
||||
},
|
||||
{
|
||||
"name": "initDomAdapter"
|
||||
},
|
||||
|
|
|
@ -11,17 +11,18 @@ import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
|
|||
|
||||
import {defineComponent} from '../../src/render3/definition';
|
||||
import {bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di';
|
||||
import {NgOnChangesFeature, PublicFeature, defineDirective, directiveInject, injectChangeDetectorRef, injectElementRef, injectRenderer2, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
|
||||
import {PublicFeature, defineDirective, directiveInject, injectChangeDetectorRef, injectElementRef, injectRenderer2, injectTemplateRef, injectViewContainerRef, load} from '../../src/render3/index';
|
||||
import {bind, container, containerRefreshEnd, containerRefreshStart, createNodeAtIndex, createLViewData, createTView, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, projection, projectionDef, reference, template, text, textBinding, loadDirective, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions';
|
||||
import {LInjector} from '../../src/render3/interfaces/injector';
|
||||
import {isProceduralRenderer} from '../../src/render3/interfaces/renderer';
|
||||
import {AttributeMarker, TNodeType} from '../../src/render3/interfaces/node';
|
||||
import {AttributeMarker, LContainerNode, LElementNode, TNodeType} from '../../src/render3/interfaces/node';
|
||||
|
||||
import {LViewFlags} from '../../src/render3/interfaces/view';
|
||||
import {ViewRef} from '../../src/render3/view_ref';
|
||||
|
||||
import {getRendererFactory2} from './imported_renderer2';
|
||||
import {ComponentFixture, createComponent, createDirective, renderComponent, toHtml} from './render_util';
|
||||
import {NgIf} from './common_with_def';
|
||||
|
||||
describe('di', () => {
|
||||
describe('no dependencies', () => {
|
||||
|
@ -787,6 +788,10 @@ describe('di', () => {
|
|||
|
||||
describe('ElementRef', () => {
|
||||
it('should create directive with ElementRef dependencies', () => {
|
||||
let dir !: Directive;
|
||||
let dirSameInstance !: DirectiveSameInstance;
|
||||
let divNode !: LElementNode;
|
||||
|
||||
class Directive {
|
||||
value: string;
|
||||
constructor(public elementRef: ElementRef) {
|
||||
|
@ -795,47 +800,75 @@ describe('di', () => {
|
|||
static ngDirectiveDef = defineDirective({
|
||||
type: Directive,
|
||||
selectors: [['', 'dir', '']],
|
||||
factory: () => new Directive(injectElementRef()),
|
||||
factory: () => dir = new Directive(injectElementRef()),
|
||||
features: [PublicFeature],
|
||||
exportAs: 'dir'
|
||||
});
|
||||
}
|
||||
|
||||
class DirectiveSameInstance {
|
||||
value: boolean;
|
||||
constructor(elementRef: ElementRef, directive: Directive) {
|
||||
this.value = (elementRef === directive.elementRef) && elementRef instanceof ElementRef;
|
||||
isSameInstance: boolean;
|
||||
constructor(public elementRef: ElementRef, directive: Directive) {
|
||||
this.isSameInstance = elementRef === directive.elementRef;
|
||||
}
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: DirectiveSameInstance,
|
||||
selectors: [['', 'dirSame', '']],
|
||||
factory: () => new DirectiveSameInstance(injectElementRef(), directiveInject(Directive)),
|
||||
factory: () => dirSameInstance =
|
||||
new DirectiveSameInstance(injectElementRef(), directiveInject(Directive)),
|
||||
exportAs: 'dirSame'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* <div dir dirSame #dirSame="dirSame" #dir="dir">
|
||||
* {{ dir.value }} - {{ dirSame.value }}
|
||||
* </div>
|
||||
*/
|
||||
/** <div dir dirSame></div> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dirSame', 'dirSame', 'dir', 'dir']);
|
||||
{ text(3); }
|
||||
elementStart(0, 'div', ['dir', '', 'dirSame', '']);
|
||||
elementEnd();
|
||||
divNode = load(0);
|
||||
}
|
||||
|
||||
if (rf & RenderFlags.Update) {
|
||||
const tmp1 = reference(1) as any;
|
||||
const tmp2 = reference(2) as any;
|
||||
textBinding(3, interpolation2('', tmp2.value, '-', tmp1.value, ''));
|
||||
}
|
||||
}, 4, 2, [Directive, DirectiveSameInstance]);
|
||||
}, 1, 0, [Directive, DirectiveSameInstance]);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(fixture.html).toEqual('<div dir="" dirsame="">ElementRef-true</div>');
|
||||
expect(dir.value).toEqual('ElementRef');
|
||||
expect(dir.elementRef.nativeElement).toEqual(divNode.native);
|
||||
expect(dirSameInstance.elementRef.nativeElement).toEqual(divNode.native);
|
||||
|
||||
// Each ElementRef instance should be unique
|
||||
expect(dirSameInstance.isSameInstance).toBe(false);
|
||||
});
|
||||
|
||||
it('should create ElementRef with comment if requesting directive is on <ng-template> node',
|
||||
() => {
|
||||
let dir !: Directive;
|
||||
let commentNode !: LContainerNode;
|
||||
|
||||
class Directive {
|
||||
value: string;
|
||||
constructor(public elementRef: ElementRef) {
|
||||
this.value = (elementRef.constructor as any).name;
|
||||
}
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: Directive,
|
||||
selectors: [['', 'dir', '']],
|
||||
factory: () => dir = new Directive(injectElementRef()),
|
||||
features: [PublicFeature],
|
||||
exportAs: 'dir'
|
||||
});
|
||||
}
|
||||
|
||||
/** <ng-template dir></ng-template> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
template(0, () => {}, 0, 0, null, ['dir', '']);
|
||||
commentNode = load(0);
|
||||
}
|
||||
}, 1, 0, [Directive]);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(dir.value).toEqual('ElementRef');
|
||||
expect(dir.elementRef.nativeElement).toEqual(commentNode.native);
|
||||
});
|
||||
});
|
||||
|
||||
describe('TemplateRef', () => {
|
||||
|
@ -855,9 +888,9 @@ describe('di', () => {
|
|||
}
|
||||
|
||||
class DirectiveSameInstance {
|
||||
value: boolean;
|
||||
isSameInstance: boolean;
|
||||
constructor(templateRef: TemplateRef<any>, directive: Directive) {
|
||||
this.value = templateRef === directive.templateRef;
|
||||
this.isSameInstance = templateRef === directive.templateRef;
|
||||
}
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: DirectiveSameInstance,
|
||||
|
@ -881,12 +914,13 @@ describe('di', () => {
|
|||
if (rf & RenderFlags.Update) {
|
||||
const tmp1 = reference(1) as any;
|
||||
const tmp2 = reference(2) as any;
|
||||
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.value, ''));
|
||||
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.isSameInstance, ''));
|
||||
}
|
||||
}, 4, 2, [Directive, DirectiveSameInstance]);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(fixture.html).toEqual('TemplateRef-true');
|
||||
// Each TemplateRef instance should be unique
|
||||
expect(fixture.html).toEqual('TemplateRef-false');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -907,9 +941,9 @@ describe('di', () => {
|
|||
}
|
||||
|
||||
class DirectiveSameInstance {
|
||||
value: boolean;
|
||||
isSameInstance: boolean;
|
||||
constructor(viewContainerRef: ViewContainerRef, directive: Directive) {
|
||||
this.value = viewContainerRef === directive.viewContainerRef;
|
||||
this.isSameInstance = viewContainerRef === directive.viewContainerRef;
|
||||
}
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: DirectiveSameInstance,
|
||||
|
@ -934,12 +968,13 @@ describe('di', () => {
|
|||
if (rf & RenderFlags.Update) {
|
||||
const tmp1 = reference(1) as any;
|
||||
const tmp2 = reference(2) as any;
|
||||
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.value, ''));
|
||||
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.isSameInstance, ''));
|
||||
}
|
||||
}, 4, 2, [Directive, DirectiveSameInstance]);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(fixture.html).toEqual('<div dir="" dirsame="">ViewContainerRef-true</div>');
|
||||
// Each ViewContainerRef instance should be unique
|
||||
expect(fixture.html).toEqual('<div dir="" dirsame="">ViewContainerRef-false</div>');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -990,53 +1025,33 @@ describe('di', () => {
|
|||
});
|
||||
}
|
||||
|
||||
class IfDirective {
|
||||
/* @Input */
|
||||
myIf = true;
|
||||
const directives = [MyComp, Directive, DirectiveSameInstance, NgIf];
|
||||
|
||||
constructor(public template: TemplateRef<any>, public vcr: ViewContainerRef) {}
|
||||
it('should inject current component ChangeDetectorRef into directives on the same node as components',
|
||||
() => {
|
||||
/** <my-comp dir dirSameInstance #dir="dir"></my-comp> {{ dir.value }} */
|
||||
const MyApp = createComponent('my-app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
element(0, 'my-comp', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
|
||||
text(2);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const tmp = reference(1) as any;
|
||||
textBinding(2, bind(tmp.value));
|
||||
}
|
||||
}, 3, 1, directives);
|
||||
|
||||
ngOnChanges() {
|
||||
if (this.myIf) {
|
||||
this.vcr.createEmbeddedView(this.template);
|
||||
}
|
||||
}
|
||||
const app = renderComponent(MyApp);
|
||||
// ChangeDetectorRef is the token, ViewRef has historically been the constructor
|
||||
expect(toHtml(app)).toEqual('<my-comp dir="" dirsame=""></my-comp>ViewRef');
|
||||
expect((comp !.cdr as ViewRef<MyComp>).context).toBe(comp);
|
||||
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: IfDirective,
|
||||
selectors: [['', 'myIf', '']],
|
||||
factory: () => new IfDirective(injectTemplateRef(), injectViewContainerRef()),
|
||||
inputs: {myIf: 'myIf'},
|
||||
features: [PublicFeature, NgOnChangesFeature]
|
||||
});
|
||||
}
|
||||
// Each ChangeDetectorRef instance should be unique
|
||||
expect(dir !.cdr).not.toBe(comp !.cdr);
|
||||
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
|
||||
});
|
||||
|
||||
|
||||
const directives = [MyComp, Directive, DirectiveSameInstance, IfDirective];
|
||||
|
||||
it('should inject current component ChangeDetectorRef into directives on components', () => {
|
||||
/** <my-comp dir dirSameInstance #dir="dir"></my-comp> {{ dir.value }} */
|
||||
const MyApp = createComponent('my-app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
element(0, 'my-comp', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
|
||||
text(2);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const tmp = reference(1) as any;
|
||||
textBinding(2, bind(tmp.value));
|
||||
}
|
||||
}, 3, 1, directives);
|
||||
|
||||
const app = renderComponent(MyApp);
|
||||
// ChangeDetectorRef is the token, ViewRef has historically been the constructor
|
||||
expect(toHtml(app)).toEqual('<my-comp dir="" dirsame=""></my-comp>ViewRef');
|
||||
expect((comp !.cdr as ViewRef<MyComp>).context).toBe(comp);
|
||||
|
||||
expect(dir !.cdr).toBe(comp !.cdr);
|
||||
expect(dir !.cdr).toBe(dirSameInstance !.cdr);
|
||||
});
|
||||
|
||||
it('should inject host component ChangeDetectorRef into directives on elements', () => {
|
||||
it('should inject host component ChangeDetectorRef into directives on normal elements', () => {
|
||||
|
||||
class MyApp {
|
||||
constructor(public cdr: ChangeDetectorRef) {}
|
||||
|
@ -1067,49 +1082,52 @@ describe('di', () => {
|
|||
expect(toHtml(app)).toEqual('<div dir="" dirsame="">ViewRef</div>');
|
||||
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
|
||||
|
||||
expect(dir !.cdr).toBe(app.cdr);
|
||||
expect(dir !.cdr).toBe(dirSameInstance !.cdr);
|
||||
// Each ChangeDetectorRef instance should be unique
|
||||
expect(dir !.cdr).not.toBe(app.cdr);
|
||||
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
|
||||
});
|
||||
|
||||
it('should inject host component ChangeDetectorRef into directives in ContentChildren', () => {
|
||||
class MyApp {
|
||||
constructor(public cdr: ChangeDetectorRef) {}
|
||||
it('should inject host component ChangeDetectorRef into directives in a component\'s ContentChildren',
|
||||
() => {
|
||||
class MyApp {
|
||||
constructor(public cdr: ChangeDetectorRef) {}
|
||||
|
||||
static ngComponentDef = defineComponent({
|
||||
type: MyApp,
|
||||
selectors: [['my-app']],
|
||||
consts: 4,
|
||||
vars: 1,
|
||||
factory: () => new MyApp(injectChangeDetectorRef()),
|
||||
/**
|
||||
* <my-comp>
|
||||
* <div dir dirSameInstance #dir="dir"></div>
|
||||
* </my-comp>
|
||||
* {{ dir.value }}
|
||||
*/
|
||||
template: function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
elementStart(0, 'my-comp');
|
||||
{ element(1, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']); }
|
||||
elementEnd();
|
||||
text(3);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const tmp = reference(2) as any;
|
||||
textBinding(3, bind(tmp.value));
|
||||
}
|
||||
},
|
||||
directives: directives
|
||||
});
|
||||
}
|
||||
static ngComponentDef = defineComponent({
|
||||
type: MyApp,
|
||||
selectors: [['my-app']],
|
||||
consts: 4,
|
||||
vars: 1,
|
||||
factory: () => new MyApp(injectChangeDetectorRef()),
|
||||
/**
|
||||
* <my-comp>
|
||||
* <div dir dirSameInstance #dir="dir"></div>
|
||||
* </my-comp>
|
||||
* {{ dir.value }}
|
||||
*/
|
||||
template: function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
elementStart(0, 'my-comp');
|
||||
{ element(1, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']); }
|
||||
elementEnd();
|
||||
text(3);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const tmp = reference(2) as any;
|
||||
textBinding(3, bind(tmp.value));
|
||||
}
|
||||
},
|
||||
directives: directives
|
||||
});
|
||||
}
|
||||
|
||||
const app = renderComponent(MyApp);
|
||||
expect(toHtml(app)).toEqual('<my-comp><div dir="" dirsame=""></div></my-comp>ViewRef');
|
||||
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
|
||||
const app = renderComponent(MyApp);
|
||||
expect(toHtml(app)).toEqual('<my-comp><div dir="" dirsame=""></div></my-comp>ViewRef');
|
||||
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
|
||||
|
||||
expect(dir !.cdr).toBe(app !.cdr);
|
||||
expect(dir !.cdr).toBe(dirSameInstance !.cdr);
|
||||
});
|
||||
// Each ChangeDetectorRef instance should be unique
|
||||
expect(dir !.cdr).not.toBe(app !.cdr);
|
||||
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
|
||||
});
|
||||
|
||||
it('should inject host component ChangeDetectorRef into directives in embedded views', () => {
|
||||
|
||||
|
@ -1161,8 +1179,9 @@ describe('di', () => {
|
|||
expect(toHtml(app)).toEqual('<div dir="" dirsame="">ViewRef</div>');
|
||||
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
|
||||
|
||||
expect(dir !.cdr).toBe(app.cdr);
|
||||
expect(dir !.cdr).toBe(dirSameInstance !.cdr);
|
||||
// Each ChangeDetectorRef instance should be unique
|
||||
expect(dir !.cdr).not.toBe(app.cdr);
|
||||
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
|
||||
});
|
||||
|
||||
it('should inject host component ChangeDetectorRef into directives on containers', () => {
|
||||
|
@ -1189,10 +1208,10 @@ describe('di', () => {
|
|||
factory: () => new MyApp(injectChangeDetectorRef()),
|
||||
consts: 1,
|
||||
vars: 0,
|
||||
/** <div *myIf="showing" dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */
|
||||
/** <div *ngIf="showing" dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */
|
||||
template: function(rf: RenderFlags, ctx: MyApp) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
template(0, C1, 3, 1, null, ['myIf', 'showing']);
|
||||
template(0, C1, 3, 1, null, ['ngIf', 'showing']);
|
||||
}
|
||||
},
|
||||
directives: directives
|
||||
|
@ -1203,8 +1222,9 @@ describe('di', () => {
|
|||
expect(toHtml(app)).toEqual('<div dir="" dirsame="">ViewRef</div>');
|
||||
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
|
||||
|
||||
expect(dir !.cdr).toBe(app.cdr);
|
||||
expect(dir !.cdr).toBe(dirSameInstance !.cdr);
|
||||
// Each ChangeDetectorRef instance should be unique
|
||||
expect(dir !.cdr).not.toBe(app.cdr);
|
||||
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core';
|
|||
import {RenderFlags} from '@angular/core/src/render3';
|
||||
|
||||
import {RendererStyleFlags2, RendererType2} from '../../src/render/api';
|
||||
import {getOrCreateNodeInjectorForNode, getOrCreateTemplateRef} from '../../src/render3/di';
|
||||
import {createTemplateRef, getOrCreateNodeInjectorForNode} from '../../src/render3/di';
|
||||
import {AttributeMarker, defineComponent, defineDirective, injectElementRef, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
|
||||
|
||||
import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, element, elementAttribute, elementClassProp, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, elementStyleProp, elementStyling, elementStylingApply, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, listener, load, loadDirective, projection, projectionDef, text, textBinding, template} from '../../src/render3/instructions';
|
||||
|
|
Loading…
Reference in New Issue