diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index 3049cd8de2..9bc5fa88ca 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -139,7 +139,7 @@ export function renderComponent( }; const rootView: LView = createLView( rendererFactory.createRenderer(hostNode, componentDef.rendererType), - createTView(-1, null, null), null, rootContext, + createTView(-1, null, null, null), rootContext, componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways); rootView.injector = opts.injector || null; @@ -160,7 +160,7 @@ export function renderComponent( executeInitAndContentHooks(); setHostBindings(ROOT_DIRECTIVE_INDICES); - detectChangesInternal(elementNode.data as LView, elementNode, componentDef, component); + detectChangesInternal(elementNode.data as LView, elementNode, component); } finally { leaveView(oldView); if (rendererFactory.end) rendererFactory.end(); diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index ba5a71bb76..1c55e79fa6 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -704,12 +704,12 @@ export function getOrCreateTemplateRef(di: LInjector): viewEngine_TemplateRef const hostTNode = hostNode.tNode; const hostTView = hostNode.view.tView; if (!hostTNode.tViews) { - hostTNode.tViews = createTView(-1, hostTView.directiveRegistry, hostTView.pipeRegistry); + hostTNode.tViews = createTView( + -1, hostNode.data.template !, hostTView.directiveRegistry, hostTView.pipeRegistry); } ngDevMode && assertNotNull(hostTNode.tViews, 'TView must be allocated'); di.templateRef = new TemplateRef( - getOrCreateElementRef(di), hostTNode.tViews as TView, hostNode.data.template !, - getRenderer(), hostNode.data.queries); + getOrCreateElementRef(di), hostTNode.tViews as TView, getRenderer(), hostNode.data.queries); } return di.templateRef; } @@ -718,15 +718,14 @@ class TemplateRef implements viewEngine_TemplateRef { readonly elementRef: viewEngine_ElementRef; constructor( - elementRef: viewEngine_ElementRef, private _tView: TView, - private _template: ComponentTemplate, private _renderer: Renderer3, + elementRef: viewEngine_ElementRef, private _tView: TView, private _renderer: Renderer3, private _queries: LQueries|null) { this.elementRef = elementRef; } createEmbeddedView(context: T): viewEngine_EmbeddedViewRef { - const viewNode = renderEmbeddedTemplate( - null, this._tView, this._template, context, this._renderer, this._queries); - return new EmbeddedViewRef(viewNode, this._template, context); + const viewNode = + renderEmbeddedTemplate(null, this._tView, context, this._renderer, this._queries); + return new EmbeddedViewRef(viewNode, this._tView.template !as ComponentTemplate, context); } } diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 5c1fdcad56..d485c11202 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -303,8 +303,8 @@ export function executeInitAndContentHooks(): void { } export function createLView( - renderer: Renderer3, tView: TView, template: ComponentTemplate| null, context: T | null, - flags: LViewFlags, sanitizer?: Sanitizer | null): LView { + renderer: Renderer3, tView: TView, context: T | null, flags: LViewFlags, + sanitizer?: Sanitizer | null): LView { const newView = { parent: currentView, flags: flags | LViewFlags.CreationMode | LViewFlags.Attached | LViewFlags.RunInit, @@ -317,7 +317,6 @@ export function createLView( tail: null, next: null, bindingIndex: -1, - template: template, context: context, queries: null, injector: currentView && currentView.injector, @@ -469,8 +468,8 @@ export function renderTemplate( host = createLNode( -1, TNodeType.Element, hostNode, null, null, createLView( - providedRendererFactory.createRenderer(null, null), tView, null, {}, - LViewFlags.CheckAlways, sanitizer)); + providedRendererFactory.createRenderer(null, null), tView, {}, LViewFlags.CheckAlways, + sanitizer)); } const hostView = host.data !; ngDevMode && assertNotNull(hostView, 'Host node should have an LView defined in host.data.'); @@ -489,8 +488,8 @@ export function renderTemplate( * TView for dynamically created views on their host TNode, which only has one instance. */ export function renderEmbeddedTemplate( - viewNode: LViewNode | null, tView: TView, template: ComponentTemplate, context: T, - renderer: Renderer3, queries?: LQueries | null): LViewNode { + viewNode: LViewNode | null, tView: TView, context: T, renderer: Renderer3, + queries?: LQueries | null): LViewNode { const _isParent = isParent; const _previousOrParentNode = previousOrParentNode; let oldView: LView; @@ -500,8 +499,8 @@ export function renderEmbeddedTemplate( previousOrParentNode = null !; if (viewNode == null) { - const lView = createLView( - renderer, tView, template, context, LViewFlags.CheckAlways, getCurrentSanitizer()); + const lView = + createLView(renderer, tView, context, LViewFlags.CheckAlways, getCurrentSanitizer()); if (queries) { lView.queries = queries.createView(); @@ -511,7 +510,7 @@ export function renderEmbeddedTemplate( rf = RenderFlags.Create; } oldView = enterView(viewNode.data, viewNode); - template(rf, context); + tView.template !(rf, context); if (rf & RenderFlags.Update) { refreshView(); } else { @@ -788,7 +787,7 @@ function getOrCreateTView( // and not on embedded templates. return template.ngPrivateData || - (template.ngPrivateData = createTView(-1, directives, pipes) as never); + (template.ngPrivateData = createTView(-1, template, directives, pipes) as never); } /** @@ -799,11 +798,12 @@ function getOrCreateTView( * @param pipes Registry of pipes for this view */ export function createTView( - viewIndex: number, directives: DirectiveDefListOrFactory | null, - pipes: PipeDefListOrFactory | null): TView { + viewIndex: number, template: ComponentTemplate| null, + directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null): TView { ngDevMode && ngDevMode.tView++; return { id: viewIndex, + template: template, node: null !, data: [], childIndex: -1, // Children set in addToViewTree(), if any @@ -887,7 +887,7 @@ export function hostElement( const node = createLNode( 0, TNodeType.Element, rNode, null, null, createLView( - renderer, getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs), null, null, + renderer, getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs), null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer)); if (firstTemplatePass) { @@ -1337,7 +1337,7 @@ function addComponentLogic(index: number, instance: T, def: ComponentDef): currentView, previousOrParentNode.tNode.index as number, createLView( rendererFactory.createRenderer(previousOrParentNode.native as RElement, def.rendererType), - tView, null, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, + 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, @@ -1592,8 +1592,7 @@ function refreshDynamicChildren() { // The directives and pipes are not needed here as an existing view is only being refreshed. const dynamicView = lViewNode.data; ngDevMode && assertNotNull(dynamicView.tView, 'TView must be allocated'); - renderEmbeddedTemplate( - lViewNode, dynamicView.tView, dynamicView.template !, dynamicView.context !, renderer); + renderEmbeddedTemplate(lViewNode, dynamicView.tView, dynamicView.context !, renderer); } } } @@ -1653,8 +1652,8 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags { } else { // When we create a new LView, we always reset the state of the instructions. const newView = createLView( - renderer, getOrCreateEmbeddedTView(viewBlockId, container), null, null, - LViewFlags.CheckAlways, getCurrentSanitizer()); + renderer, getOrCreateEmbeddedTView(viewBlockId, container), null, LViewFlags.CheckAlways, + getCurrentSanitizer()); if (lContainer.queries) { newView.queries = lContainer.queries.createView(); @@ -1685,7 +1684,7 @@ function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TV if (viewIndex >= containerTViews.length || containerTViews[viewIndex] == null) { const tView = currentView.tView; containerTViews[viewIndex] = - createTView(viewIndex, tView.directiveRegistry, tView.pipeRegistry); + createTView(viewIndex, null, tView.directiveRegistry, tView.pipeRegistry); } return containerTViews[viewIndex]; } @@ -1760,10 +1759,7 @@ export function componentRefresh(directiveIndex: number, elementIndex: number // Only attached CheckAlways components or attached, dirty OnPush components should be checked if (viewAttached(hostView) && hostView.flags & (LViewFlags.CheckAlways | LViewFlags.Dirty)) { ngDevMode && assertDataInRange(directiveIndex, directives !); - const def = currentView.tView.directives ![directiveIndex] as ComponentDef; - - detectChangesInternal( - hostView, element, def, getDirectiveInstance(directives ![directiveIndex])); + detectChangesInternal(hostView, element, getDirectiveInstance(directives ![directiveIndex])); } } @@ -2078,9 +2074,7 @@ export function getRootView(component: any): LView { export function detectChanges(component: T): void { const hostNode = _getComponentHostLElementNode(component); ngDevMode && assertNotNull(hostNode.data, 'Component host node should be attached to an LView'); - const componentIndex = hostNode.tNode.flags >> TNodeFlags.DirectiveStartingIndexShift; - const def = hostNode.view.tView.directives ![componentIndex] as ComponentDef; - detectChangesInternal(hostNode.data as LView, hostNode, def, component); + detectChangesInternal(hostNode.data as LView, hostNode, component); } @@ -2100,10 +2094,9 @@ export function checkNoChanges(component: T): void { } /** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */ -export function detectChangesInternal( - hostView: LView, hostNode: LElementNode, def: ComponentDef, component: T) { +export function detectChangesInternal(hostView: LView, hostNode: LElementNode, component: T) { const oldView = enterView(hostView, hostNode); - const template = def.template; + const template = hostView.tView.template !; try { template(getRenderFlags(hostView), component); diff --git a/packages/core/src/render3/interfaces/view.ts b/packages/core/src/render3/interfaces/view.ts index 4d702169c8..fa672663fc 100644 --- a/packages/core/src/render3/interfaces/view.ts +++ b/packages/core/src/render3/interfaces/view.ts @@ -126,11 +126,6 @@ export interface LView { */ tView: TView; - /** - * For dynamically inserted views, the template function to refresh the view. - */ - template: ComponentTemplate<{}>|null; - /** * - For embedded views, the context with which to render the template. * - For root view of the root component the context contains change detection data. @@ -212,6 +207,12 @@ export interface TView { */ readonly id: number; + /** + * The template function used to refresh the view of dynamically created views + * and components. Will be null for inline views. + */ + template: ComponentTemplate<{}>|null; + /** * Pointer to the `TNode` that represents the root of the view. * diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index d4ef7d36ff..ea3d413d31 100644 --- a/packages/core/test/render3/di_spec.ts +++ b/packages/core/test/render3/di_spec.ts @@ -1404,7 +1404,7 @@ describe('di', () => { describe('getOrCreateNodeInjector', () => { it('should handle initial undefined state', () => { const contentView = - createLView(null !, createTView(-1, null, null), null, null, LViewFlags.CheckAlways); + createLView(null !, createTView(-1, null, null, null), null, LViewFlags.CheckAlways); const oldView = enterView(contentView, null !); try { const parent = createLNode(0, TNodeType.Element, null, null, null, null);