diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index 53f7d15565..7ce6ef86bb 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -138,8 +138,8 @@ export function renderComponent( clean: CLEAN_PROMISE, }; const rootView: LView = createLView( - -1, rendererFactory.createRenderer(hostNode, componentDef.rendererType), - createTView(null, null), null, rootContext, + rendererFactory.createRenderer(hostNode, componentDef.rendererType), + createTView(-1, null, null), null, rootContext, componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways); rootView.injector = opts.injector || null; diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index 9058b36421..9f7a5702cc 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -700,7 +700,7 @@ export function getOrCreateTemplateRef(di: LInjector): viewEngine_TemplateRef const hostTNode = hostNode.tNode; const hostTView = hostNode.view.tView; if (!hostTNode.tViews) { - hostTNode.tViews = createTView(hostTView.directiveRegistry, hostTView.pipeRegistry); + hostTNode.tViews = createTView(-1, hostTView.directiveRegistry, hostTView.pipeRegistry); } ngDevMode && assertNotNull(hostTNode.tViews, 'TView must be allocated'); di.templateRef = new TemplateRef( diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index ea547ab6b1..0533fa31ce 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -298,11 +298,10 @@ export function executeInitAndContentHooks(): void { } export function createLView( - viewId: number, renderer: Renderer3, tView: TView, template: ComponentTemplate| null, - context: T | null, flags: LViewFlags, sanitizer?: Sanitizer | null): LView { + renderer: Renderer3, tView: TView, template: ComponentTemplate| null, context: T | null, + flags: LViewFlags, sanitizer?: Sanitizer | null): LView { const newView = { parent: currentView, - id: viewId, // -1 for component views flags: flags | LViewFlags.CreationMode | LViewFlags.Attached | LViewFlags.RunInit, node: null !, // until we initialize it in createNode. data: [], @@ -465,7 +464,7 @@ export function renderTemplate( host = createLNode( -1, TNodeType.Element, hostNode, null, null, createLView( - -1, providedRendererFactory.createRenderer(null, null), tView, null, {}, + providedRendererFactory.createRenderer(null, null), tView, null, {}, LViewFlags.CheckAlways, sanitizer)); } const hostView = host.data !; @@ -497,7 +496,7 @@ export function renderEmbeddedTemplate( if (viewNode == null) { const lView = createLView( - -1, renderer, tView, template, context, LViewFlags.CheckAlways, getCurrentSanitizer()); + renderer, tView, template, context, LViewFlags.CheckAlways, getCurrentSanitizer()); if (queries) { lView.queries = queries.createView(); @@ -784,14 +783,22 @@ function getOrCreateTView( // and not on embedded templates. return template.ngPrivateData || - (template.ngPrivateData = createTView(directives, pipes) as never); + (template.ngPrivateData = createTView(-1, directives, pipes) as never); } -/** Creates a TView instance */ +/** + * Creates a TView instance + * + * @param viewIndex The viewBlockId for inline views, or -1 if it's a component/dynamic + * @param directives Registry of directives for this view + * @param pipes Registry of pipes for this view + */ export function createTView( - defs: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null): TView { + viewIndex: number, directives: DirectiveDefListOrFactory | null, + pipes: PipeDefListOrFactory | null): TView { ngDevMode && ngDevMode.tView++; return { + id: viewIndex, node: null !, data: [], childIndex: -1, // Children set in addToViewTree(), if any @@ -808,7 +815,7 @@ export function createTView( pipeDestroyHooks: null, hostBindings: null, components: null, - directiveRegistry: typeof defs === 'function' ? defs() : defs, + directiveRegistry: typeof directives === 'function' ? directives() : directives, pipeRegistry: typeof pipes === 'function' ? pipes() : pipes, currentMatches: null }; @@ -875,7 +882,7 @@ export function hostElement( const node = createLNode( 0, TNodeType.Element, rNode, null, null, createLView( - -1, renderer, getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs), null, null, + renderer, getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs), null, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer)); if (firstTemplatePass) { @@ -1324,7 +1331,6 @@ function addComponentLogic(index: number, instance: T, def: ComponentDef): const hostView = addToViewTree( currentView, previousOrParentNode.tNode.index as number, createLView( - -1, rendererFactory.createRenderer(previousOrParentNode.native as RElement, def.rendererType), tView, null, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, getCurrentSanitizer())); @@ -1605,7 +1611,7 @@ function scanForView( containerNode: LContainerNode, startIdx: number, viewBlockId: number): LViewNode|null { const views = containerNode.data.views; for (let i = startIdx; i < views.length; i++) { - const viewAtPositionId = views[i].data.id; + const viewAtPositionId = views[i].data.tView.id; if (viewAtPositionId === viewBlockId) { return views[i]; } else if (viewAtPositionId < viewBlockId) { @@ -1642,7 +1648,7 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags { } else { // When we create a new LView, we always reset the state of the instructions. const newView = createLView( - viewBlockId, renderer, getOrCreateEmbeddedTView(viewBlockId, container), null, null, + renderer, getOrCreateEmbeddedTView(viewBlockId, container), null, null, LViewFlags.CheckAlways, getCurrentSanitizer()); if (lContainer.queries) { @@ -1673,7 +1679,8 @@ function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TV ngDevMode && assertEqual(Array.isArray(containerTViews), true, 'TViews should be in an array'); if (viewIndex >= containerTViews.length || containerTViews[viewIndex] == null) { const tView = currentView.tView; - containerTViews[viewIndex] = createTView(tView.directiveRegistry, tView.pipeRegistry); + containerTViews[viewIndex] = + createTView(viewIndex, tView.directiveRegistry, tView.pipeRegistry); } return containerTViews[viewIndex]; } diff --git a/packages/core/src/render3/interfaces/view.ts b/packages/core/src/render3/interfaces/view.ts index 5858d8a386..942c1e0551 100644 --- a/packages/core/src/render3/interfaces/view.ts +++ b/packages/core/src/render3/interfaces/view.ts @@ -49,13 +49,6 @@ export interface LView { // TODO(kara): Remove when we have parent/child on TNodes readonly node: LViewNode|LElementNode; - /** - * ID to determine whether this view is the same as the previous view - * in this position. If it's not, we know this view needs to be inserted - * and the one that exists needs to be removed (e.g. if/else statements) - */ - readonly id: number; - /** Renderer to be used for this view. */ readonly renderer: Renderer3; @@ -207,6 +200,15 @@ export interface LViewOrLContainer { * Stored on the template function as ngPrivateData. */ export interface TView { + /** + * ID for inline views to determine whether a view is the same as the previous view + * in a certain position. If it's not, we know the new view needs to be inserted + * and the one that exists needs to be removed (e.g. if/else statements) + * + * If this is -1, then this is a component view or a dynamically created view. + */ + readonly id: number; + /** * Pointer to the `TNode` that represents the root of the view. * diff --git a/packages/core/src/render3/node_manipulation.ts b/packages/core/src/render3/node_manipulation.ts index 1b7403161a..a22c3cc088 100644 --- a/packages/core/src/render3/node_manipulation.ts +++ b/packages/core/src/render3/node_manipulation.ts @@ -426,7 +426,7 @@ function cleanUpView(view: LView): void { executeOnDestroys(view); executePipeOnDestroys(view); // For component views only, the local renderer is destroyed as clean up time. - if (view.id === -1 && isProceduralRenderer(view.renderer)) { + if (view.tView && view.tView.id === -1 && isProceduralRenderer(view.renderer)) { ngDevMode && ngDevMode.rendererDestroy++; view.renderer.destroy(); } diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index c5bceace20..d4ef7d36ff 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(-1, null !, createTView(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);