From 47f4412650357a846fa4ccc90879e65df077a370 Mon Sep 17 00:00:00 2001 From: Kara Erickson Date: Wed, 12 Sep 2018 08:47:03 -0700 Subject: [PATCH] refactor(ivy): LContainers should store views not nodes (#25933) PR Close #25933 --- packages/core/src/render3/component_ref.ts | 9 +-- packages/core/src/render3/di.ts | 4 +- packages/core/src/render3/instructions.ts | 41 +++++++------- .../core/src/render3/interfaces/container.ts | 2 +- .../core/src/render3/node_manipulation.ts | 55 +++++++++---------- 5 files changed, 53 insertions(+), 58 deletions(-) diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index 8fdac685ca..9cbd5bf871 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -136,6 +136,7 @@ export class ComponentFactory extends viewEngine_ComponentFactory { // Create element node at index 0 in data array elementNode = hostElement(componentTag, hostNode, this.componentDef); + const componentView = elementNode.data as LViewData; // Create directive instance with factory() and store at index 0 in directives array component = @@ -144,8 +145,8 @@ export class ComponentFactory extends viewEngine_ComponentFactory { queueHostBindingForCheck(0, this.componentDef.hostVars); } rootContext.components.push(component); - initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data !); - (elementNode.data as LViewData)[CONTEXT] = component; + initChangeDetectorIfExisting(elementNode.nodeInjector, component, componentView); + componentView[CONTEXT] = component; // TODO: should LifecycleHooksFeature and other host features be generated by the compiler and // executed here? // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref @@ -178,8 +179,8 @@ export class ComponentFactory extends viewEngine_ComponentFactory { } // Execute the template in creation mode only, and then turn off the CreationMode flag - renderEmbeddedTemplate(elementNode, elementNode.data ![TVIEW], component, RenderFlags.Create); - elementNode.data ![FLAGS] &= ~LViewFlags.CreationMode; + renderEmbeddedTemplate(componentView, componentView[TVIEW], component, RenderFlags.Create); + componentView[FLAGS] &= ~LViewFlags.CreationMode; } finally { enterView(oldView, null); if (rendererFactory.end) rendererFactory.end(); diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index 71474845ee..17cf5e5c8f 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -733,7 +733,7 @@ class ViewContainerRef extends viewEngine_ViewContainerRef { insertView(this._lContainerNode, lViewNode, adjustedIdx); const views = this._lContainerNode.data[VIEWS]; const beforeNode = adjustedIdx + 1 < views.length ? - (getChildLNode(views[adjustedIdx + 1]) !).native : + (getChildLNode(views[adjustedIdx + 1][HOST_NODE]) !).native : this._lContainerNode.native; addRemoveViewFromContainer(this._lContainerNode, lViewNode.data, true, beforeNode); @@ -835,7 +835,7 @@ class TemplateRef extends viewEngine_TemplateRef { if (containerNode) { insertView(containerNode, viewNode, index !); } - renderEmbeddedTemplate(viewNode, this._tView, context, RenderFlags.Create); + renderEmbeddedTemplate(viewNode.data, this._tView, context, RenderFlags.Create); const viewRef = new ViewRef(viewNode.data, context); viewRef._lViewNode = viewNode; return viewRef; diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 04a11d3558..afdc77df45 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -606,26 +606,25 @@ export function createEmbeddedViewNode( * TView for dynamically created views on their host TNode, which only has one instance. */ export function renderEmbeddedTemplate( - viewNode: LViewNode | LElementNode, tView: TView, context: T, rf: RenderFlags): LViewNode| - LElementNode { + viewToRender: LViewData, tView: TView, context: T, rf: RenderFlags) { const _isParent = isParent; const _previousOrParentTNode = previousOrParentTNode; let oldView: LViewData; - if (viewNode.data ![PARENT] == null && viewNode.data ![CONTEXT] && !tView.template) { + if (viewToRender[PARENT] == null && viewToRender[CONTEXT] && !tView.template) { // This is a root view inside the view tree - tickRootContext(viewNode.data ![CONTEXT] as RootContext); + tickRootContext(viewToRender[CONTEXT] as RootContext); } else { try { isParent = true; previousOrParentTNode = null !; - oldView = enterView(viewNode.data !, tView.node); + oldView = enterView(viewToRender, tView.node); namespaceHTML(); tView.template !(rf, context); if (rf & RenderFlags.Update) { refreshDescendantViews(); } else { - viewNode.data ![TVIEW].firstTemplatePass = firstTemplatePass = false; + viewToRender[TVIEW].firstTemplatePass = firstTemplatePass = false; } } finally { // renderEmbeddedTemplate() is called twice in fact, once for creation only and then once for @@ -636,7 +635,6 @@ export function renderEmbeddedTemplate( previousOrParentTNode = _previousOrParentTNode; } } - return viewNode; } /** @@ -2039,12 +2037,12 @@ function refreshDynamicEmbeddedViews(lViewData: LViewData) { if (current.length < HEADER_OFFSET && current[ACTIVE_INDEX] === null) { const container = current as LContainer; for (let i = 0; i < container[VIEWS].length; i++) { - const lViewNode = container[VIEWS][i]; + const dynamicViewData = container[VIEWS][i]; // The directives and pipes are not needed here as an existing view is only being refreshed. - const dynamicViewData = lViewNode.data; ngDevMode && assertDefined(dynamicViewData[TVIEW], 'TView must be allocated'); renderEmbeddedTemplate( - lViewNode, dynamicViewData[TVIEW], dynamicViewData[CONTEXT] !, RenderFlags.Update); + dynamicViewData, dynamicViewData[TVIEW], dynamicViewData[CONTEXT] !, + RenderFlags.Update); } } } @@ -2061,10 +2059,10 @@ function refreshDynamicEmbeddedViews(lViewData: LViewData) { * @returns index of a found view or -1 if not found */ function scanForView( - containerNode: LContainerNode, startIdx: number, viewBlockId: number): LViewNode|null { + containerNode: LContainerNode, startIdx: number, viewBlockId: number): LViewData|null { const views = containerNode.data[VIEWS]; for (let i = startIdx; i < views.length; i++) { - const viewAtPositionId = views[i].data[TVIEW].id; + const viewAtPositionId = views[i][TVIEW].id; if (viewAtPositionId === viewBlockId) { return views[i]; } else if (viewAtPositionId < viewBlockId) { @@ -2096,25 +2094,26 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num ngDevMode && assertNodeType(containerTNode, TNodeType.Container); const lContainer = container.data; - let viewNode: LViewNode|null = scanForView(container, lContainer[ACTIVE_INDEX] !, viewBlockId); + let viewNode: LViewNode|null; + let viewToRender = scanForView(container, lContainer[ACTIVE_INDEX] !, viewBlockId); - if (viewNode) { - const embeddedView = viewNode.data; + if (viewToRender) { isParent = true; - enterView(embeddedView, embeddedView[TVIEW].node); + viewNode = viewToRender[HOST_NODE] as LViewNode; + enterView(viewToRender, viewToRender[TVIEW].node); } else { // When we create a new LView, we always reset the state of the instructions. - const newView = createLViewData( + viewToRender = createLViewData( renderer, getOrCreateEmbeddedTView(viewBlockId, consts, vars, containerTNode as TContainerNode), null, LViewFlags.CheckAlways, getCurrentSanitizer()); if (lContainer[QUERIES]) { - newView[QUERIES] = lContainer[QUERIES] !.createView(); + viewToRender[QUERIES] = lContainer[QUERIES] !.createView(); } - viewNode = createLNode(viewBlockId, TNodeType.View, null, null, null, newView); - enterView(newView, newView[TVIEW].node); + viewNode = createLNode(viewBlockId, TNodeType.View, null, null, null, viewToRender); + enterView(viewToRender, viewToRender[TVIEW].node); } if (container) { if (creationMode) { @@ -2123,7 +2122,7 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num } lContainer[ACTIVE_INDEX] !++; } - return getRenderFlags(viewNode.data); + return getRenderFlags(viewToRender); } /** diff --git a/packages/core/src/render3/interfaces/container.ts b/packages/core/src/render3/interfaces/container.ts index 402aa95afc..c8cfd9e6ca 100644 --- a/packages/core/src/render3/interfaces/container.ts +++ b/packages/core/src/render3/interfaces/container.ts @@ -64,7 +64,7 @@ export interface LContainer extends Array { * (and don't need to be re-added) and so we can remove views from the DOM when they * are no longer required. */ - [VIEWS]: LViewNode[]; + [VIEWS]: LViewData[]; /** * Parent Element which will contain the location where all of the Views will be diff --git a/packages/core/src/render3/node_manipulation.ts b/packages/core/src/render3/node_manipulation.ts index 7b9a57bdf9..e66464182b 100644 --- a/packages/core/src/render3/node_manipulation.ts +++ b/packages/core/src/render3/node_manipulation.ts @@ -119,7 +119,7 @@ function walkTNodeTree( } if (childContainerData[VIEWS].length) { - currentView = childContainerData[VIEWS][0].data; + currentView = childContainerData[VIEWS][0]; nextTNode = currentView[TVIEW].node; // When the walker enters a container, then the beforeNode has to become the local native @@ -293,7 +293,7 @@ export function destroyViewTree(rootView: LViewData): void { } else { // If container, traverse down to its first LViewData. const container = viewOrContainer as LContainer; - if (container[VIEWS].length) next = container[VIEWS][0].data; + if (container[VIEWS].length) next = container[VIEWS][0]; } if (next == null) { @@ -323,22 +323,21 @@ export function destroyViewTree(rootView: LViewData): void { * @param index The index at which to insert the view * @returns The inserted view */ -export function insertView( - container: LContainerNode, viewNode: LViewNode, index: number): LViewNode { +export function insertView(container: LContainerNode, viewNode: LViewNode, index: number) { const state = container.data; const views = state[VIEWS]; const lView = viewNode.data as LViewData; if (index > 0) { // This is a new view, we need to add it to the children. - views[index - 1].data[NEXT] = lView; + views[index - 1][NEXT] = lView; } if (index < views.length) { - lView[NEXT] = views[index].data; - views.splice(index, 0, viewNode); + lView[NEXT] = views[index]; + views.splice(index, 0, lView); } else { - views.push(viewNode); + views.push(lView); lView[NEXT] = null; } @@ -356,8 +355,6 @@ export function insertView( // Sets the attached flag lView[FLAGS] |= LViewFlags.Attached; - - return viewNode; } /** @@ -370,26 +367,25 @@ export function insertView( * @param removeIndex The index of the view to detach * @returns The detached view */ -export function detachView(container: LContainerNode, removeIndex: number): LViewNode { +export function detachView(container: LContainerNode, removeIndex: number) { const views = container.data[VIEWS]; - const viewNode = views[removeIndex]; + const viewToDetach = views[removeIndex]; + const viewNode = viewToDetach[HOST_NODE] as LViewNode; if (removeIndex > 0) { - views[removeIndex - 1].data[NEXT] = viewNode.data[NEXT] as LViewData; + views[removeIndex - 1][NEXT] = viewToDetach[NEXT] as LViewData; } views.splice(removeIndex, 1); if (!container.tNode.detached) { - addRemoveViewFromContainer(container, viewNode.data, false); + addRemoveViewFromContainer(container, viewToDetach, false); } - // Notify query that view has been removed - const removedLView = viewNode.data; - if (removedLView[QUERIES]) { - removedLView[QUERIES] !.removeView(); + + if (viewToDetach[QUERIES]) { + viewToDetach[QUERIES] !.removeView(); } - removedLView[CONTAINER_INDEX] = -1; + viewToDetach[CONTAINER_INDEX] = -1; (viewNode as{view: LViewData | null}).view = null; // Unsets the attached flag - viewNode.data[FLAGS] &= ~LViewFlags.Attached; - return viewNode; + viewToDetach[FLAGS] &= ~LViewFlags.Attached; } /** @@ -399,11 +395,10 @@ export function detachView(container: LContainerNode, removeIndex: number): LVie * @param removeIndex The index of the view to remove * @returns The removed view */ -export function removeView(container: LContainerNode, removeIndex: number): LViewNode { - const viewNode = container.data[VIEWS][removeIndex]; - destroyLView(viewNode.data); +export function removeView(container: LContainerNode, removeIndex: number) { + const viewToRemove = container.data[VIEWS][removeIndex]; + destroyLView(viewToRemove); detachView(container, removeIndex); - return viewNode; } /** Gets the child of the given LViewData */ @@ -644,9 +639,10 @@ export function appendChild(parent: LNode, child: RNode | null, currentView: LVi const container = getParentLNode(parent) as LContainerNode; const renderParent = container.data[RENDER_PARENT]; const views = container.data[VIEWS]; - const index = views.indexOf(parent as LViewNode); - const beforeNode = - index + 1 < views.length ? (getChildLNode(views[index + 1]) !).native : container.native; + const index = views.indexOf(currentView); + const beforeNode = index + 1 < views.length ? + (getChildLNode(views[index + 1][HOST_NODE]) !).native : + container.native; nativeInsertBefore(renderer, renderParent !.native, child, beforeNode); } else if (parent.tNode.type === TNodeType.ElementContainer) { const beforeNode = parent.native; @@ -717,8 +713,7 @@ export function appendProjectedNode( lContainer[RENDER_PARENT] = renderParent; const views = lContainer[VIEWS]; for (let i = 0; i < views.length; i++) { - const viewNode = views[i]; - addRemoveViewFromContainer(node as LContainerNode, viewNode.data, true, node.native); + addRemoveViewFromContainer(node as LContainerNode, views[i], true, node.native); } } else if (node.tNode.type === TNodeType.ElementContainer) { let ngContainerChild = getChildLNode(node as LElementContainerNode);