refactor(ivy): LContainers should store views not nodes (#25933)

PR Close #25933
This commit is contained in:
Kara Erickson 2018-09-12 08:47:03 -07:00 committed by Ben Lesh
parent a09c3923db
commit 47f4412650
5 changed files with 53 additions and 58 deletions

View File

@ -136,6 +136,7 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
// Create element node at index 0 in data array // Create element node at index 0 in data array
elementNode = hostElement(componentTag, hostNode, this.componentDef); 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 // Create directive instance with factory() and store at index 0 in directives array
component = component =
@ -144,8 +145,8 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
queueHostBindingForCheck(0, this.componentDef.hostVars); queueHostBindingForCheck(0, this.componentDef.hostVars);
} }
rootContext.components.push(component); rootContext.components.push(component);
initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data !); initChangeDetectorIfExisting(elementNode.nodeInjector, component, componentView);
(elementNode.data as LViewData)[CONTEXT] = component; componentView[CONTEXT] = component;
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and // TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
// executed here? // executed here?
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
@ -178,8 +179,8 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
} }
// Execute the template in creation mode only, and then turn off the CreationMode flag // Execute the template in creation mode only, and then turn off the CreationMode flag
renderEmbeddedTemplate(elementNode, elementNode.data ![TVIEW], component, RenderFlags.Create); renderEmbeddedTemplate(componentView, componentView[TVIEW], component, RenderFlags.Create);
elementNode.data ![FLAGS] &= ~LViewFlags.CreationMode; componentView[FLAGS] &= ~LViewFlags.CreationMode;
} finally { } finally {
enterView(oldView, null); enterView(oldView, null);
if (rendererFactory.end) rendererFactory.end(); if (rendererFactory.end) rendererFactory.end();

View File

@ -733,7 +733,7 @@ class ViewContainerRef extends viewEngine_ViewContainerRef {
insertView(this._lContainerNode, lViewNode, adjustedIdx); insertView(this._lContainerNode, lViewNode, adjustedIdx);
const views = this._lContainerNode.data[VIEWS]; const views = this._lContainerNode.data[VIEWS];
const beforeNode = adjustedIdx + 1 < views.length ? const beforeNode = adjustedIdx + 1 < views.length ?
(getChildLNode(views[adjustedIdx + 1]) !).native : (getChildLNode(views[adjustedIdx + 1][HOST_NODE]) !).native :
this._lContainerNode.native; this._lContainerNode.native;
addRemoveViewFromContainer(this._lContainerNode, lViewNode.data, true, beforeNode); addRemoveViewFromContainer(this._lContainerNode, lViewNode.data, true, beforeNode);
@ -835,7 +835,7 @@ class TemplateRef<T> extends viewEngine_TemplateRef<T> {
if (containerNode) { if (containerNode) {
insertView(containerNode, viewNode, index !); 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); const viewRef = new ViewRef(viewNode.data, context);
viewRef._lViewNode = viewNode; viewRef._lViewNode = viewNode;
return viewRef; return viewRef;

View File

@ -606,26 +606,25 @@ export function createEmbeddedViewNode<T>(
* TView for dynamically created views on their host TNode, which only has one instance. * TView for dynamically created views on their host TNode, which only has one instance.
*/ */
export function renderEmbeddedTemplate<T>( export function renderEmbeddedTemplate<T>(
viewNode: LViewNode | LElementNode, tView: TView, context: T, rf: RenderFlags): LViewNode| viewToRender: LViewData, tView: TView, context: T, rf: RenderFlags) {
LElementNode {
const _isParent = isParent; const _isParent = isParent;
const _previousOrParentTNode = previousOrParentTNode; const _previousOrParentTNode = previousOrParentTNode;
let oldView: LViewData; 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 // This is a root view inside the view tree
tickRootContext(viewNode.data ![CONTEXT] as RootContext); tickRootContext(viewToRender[CONTEXT] as RootContext);
} else { } else {
try { try {
isParent = true; isParent = true;
previousOrParentTNode = null !; previousOrParentTNode = null !;
oldView = enterView(viewNode.data !, tView.node); oldView = enterView(viewToRender, tView.node);
namespaceHTML(); namespaceHTML();
tView.template !(rf, context); tView.template !(rf, context);
if (rf & RenderFlags.Update) { if (rf & RenderFlags.Update) {
refreshDescendantViews(); refreshDescendantViews();
} else { } else {
viewNode.data ![TVIEW].firstTemplatePass = firstTemplatePass = false; viewToRender[TVIEW].firstTemplatePass = firstTemplatePass = false;
} }
} finally { } finally {
// renderEmbeddedTemplate() is called twice in fact, once for creation only and then once for // renderEmbeddedTemplate() is called twice in fact, once for creation only and then once for
@ -636,7 +635,6 @@ export function renderEmbeddedTemplate<T>(
previousOrParentTNode = _previousOrParentTNode; previousOrParentTNode = _previousOrParentTNode;
} }
} }
return viewNode;
} }
/** /**
@ -2039,12 +2037,12 @@ function refreshDynamicEmbeddedViews(lViewData: LViewData) {
if (current.length < HEADER_OFFSET && current[ACTIVE_INDEX] === null) { if (current.length < HEADER_OFFSET && current[ACTIVE_INDEX] === null) {
const container = current as LContainer; const container = current as LContainer;
for (let i = 0; i < container[VIEWS].length; i++) { 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. // 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'); ngDevMode && assertDefined(dynamicViewData[TVIEW], 'TView must be allocated');
renderEmbeddedTemplate( 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 * @returns index of a found view or -1 if not found
*/ */
function scanForView( function scanForView(
containerNode: LContainerNode, startIdx: number, viewBlockId: number): LViewNode|null { containerNode: LContainerNode, startIdx: number, viewBlockId: number): LViewData|null {
const views = containerNode.data[VIEWS]; const views = containerNode.data[VIEWS];
for (let i = startIdx; i < views.length; i++) { for (let i = startIdx; i < views.length; i++) {
const viewAtPositionId = views[i].data[TVIEW].id; const viewAtPositionId = views[i][TVIEW].id;
if (viewAtPositionId === viewBlockId) { if (viewAtPositionId === viewBlockId) {
return views[i]; return views[i];
} else if (viewAtPositionId < viewBlockId) { } else if (viewAtPositionId < viewBlockId) {
@ -2096,25 +2094,26 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num
ngDevMode && assertNodeType(containerTNode, TNodeType.Container); ngDevMode && assertNodeType(containerTNode, TNodeType.Container);
const lContainer = container.data; 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) { if (viewToRender) {
const embeddedView = viewNode.data;
isParent = true; isParent = true;
enterView(embeddedView, embeddedView[TVIEW].node); viewNode = viewToRender[HOST_NODE] as LViewNode;
enterView(viewToRender, viewToRender[TVIEW].node);
} else { } else {
// When we create a new LView, we always reset the state of the instructions. // When we create a new LView, we always reset the state of the instructions.
const newView = createLViewData( viewToRender = createLViewData(
renderer, renderer,
getOrCreateEmbeddedTView(viewBlockId, consts, vars, containerTNode as TContainerNode), null, getOrCreateEmbeddedTView(viewBlockId, consts, vars, containerTNode as TContainerNode), null,
LViewFlags.CheckAlways, getCurrentSanitizer()); LViewFlags.CheckAlways, getCurrentSanitizer());
if (lContainer[QUERIES]) { if (lContainer[QUERIES]) {
newView[QUERIES] = lContainer[QUERIES] !.createView(); viewToRender[QUERIES] = lContainer[QUERIES] !.createView();
} }
viewNode = createLNode(viewBlockId, TNodeType.View, null, null, null, newView); viewNode = createLNode(viewBlockId, TNodeType.View, null, null, null, viewToRender);
enterView(newView, newView[TVIEW].node); enterView(viewToRender, viewToRender[TVIEW].node);
} }
if (container) { if (container) {
if (creationMode) { if (creationMode) {
@ -2123,7 +2122,7 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num
} }
lContainer[ACTIVE_INDEX] !++; lContainer[ACTIVE_INDEX] !++;
} }
return getRenderFlags(viewNode.data); return getRenderFlags(viewToRender);
} }
/** /**

View File

@ -64,7 +64,7 @@ export interface LContainer extends Array<any> {
* (and don't need to be re-added) and so we can remove views from the DOM when they * (and don't need to be re-added) and so we can remove views from the DOM when they
* are no longer required. * are no longer required.
*/ */
[VIEWS]: LViewNode[]; [VIEWS]: LViewData[];
/** /**
* Parent Element which will contain the location where all of the Views will be * Parent Element which will contain the location where all of the Views will be

View File

@ -119,7 +119,7 @@ function walkTNodeTree(
} }
if (childContainerData[VIEWS].length) { if (childContainerData[VIEWS].length) {
currentView = childContainerData[VIEWS][0].data; currentView = childContainerData[VIEWS][0];
nextTNode = currentView[TVIEW].node; nextTNode = currentView[TVIEW].node;
// When the walker enters a container, then the beforeNode has to become the local native // 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 { } else {
// If container, traverse down to its first LViewData. // If container, traverse down to its first LViewData.
const container = viewOrContainer as LContainer; 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) { if (next == null) {
@ -323,22 +323,21 @@ export function destroyViewTree(rootView: LViewData): void {
* @param index The index at which to insert the view * @param index The index at which to insert the view
* @returns The inserted view * @returns The inserted view
*/ */
export function insertView( export function insertView(container: LContainerNode, viewNode: LViewNode, index: number) {
container: LContainerNode, viewNode: LViewNode, index: number): LViewNode {
const state = container.data; const state = container.data;
const views = state[VIEWS]; const views = state[VIEWS];
const lView = viewNode.data as LViewData; const lView = viewNode.data as LViewData;
if (index > 0) { if (index > 0) {
// This is a new view, we need to add it to the children. // 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) { if (index < views.length) {
lView[NEXT] = views[index].data; lView[NEXT] = views[index];
views.splice(index, 0, viewNode); views.splice(index, 0, lView);
} else { } else {
views.push(viewNode); views.push(lView);
lView[NEXT] = null; lView[NEXT] = null;
} }
@ -356,8 +355,6 @@ export function insertView(
// Sets the attached flag // Sets the attached flag
lView[FLAGS] |= LViewFlags.Attached; lView[FLAGS] |= LViewFlags.Attached;
return viewNode;
} }
/** /**
@ -370,26 +367,25 @@ export function insertView(
* @param removeIndex The index of the view to detach * @param removeIndex The index of the view to detach
* @returns The detached view * @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 views = container.data[VIEWS];
const viewNode = views[removeIndex]; const viewToDetach = views[removeIndex];
const viewNode = viewToDetach[HOST_NODE] as LViewNode;
if (removeIndex > 0) { 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); views.splice(removeIndex, 1);
if (!container.tNode.detached) { 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 (viewToDetach[QUERIES]) {
if (removedLView[QUERIES]) { viewToDetach[QUERIES] !.removeView();
removedLView[QUERIES] !.removeView();
} }
removedLView[CONTAINER_INDEX] = -1; viewToDetach[CONTAINER_INDEX] = -1;
(viewNode as{view: LViewData | null}).view = null; (viewNode as{view: LViewData | null}).view = null;
// Unsets the attached flag // Unsets the attached flag
viewNode.data[FLAGS] &= ~LViewFlags.Attached; viewToDetach[FLAGS] &= ~LViewFlags.Attached;
return viewNode;
} }
/** /**
@ -399,11 +395,10 @@ export function detachView(container: LContainerNode, removeIndex: number): LVie
* @param removeIndex The index of the view to remove * @param removeIndex The index of the view to remove
* @returns The removed view * @returns The removed view
*/ */
export function removeView(container: LContainerNode, removeIndex: number): LViewNode { export function removeView(container: LContainerNode, removeIndex: number) {
const viewNode = container.data[VIEWS][removeIndex]; const viewToRemove = container.data[VIEWS][removeIndex];
destroyLView(viewNode.data); destroyLView(viewToRemove);
detachView(container, removeIndex); detachView(container, removeIndex);
return viewNode;
} }
/** Gets the child of the given LViewData */ /** 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 container = getParentLNode(parent) as LContainerNode;
const renderParent = container.data[RENDER_PARENT]; const renderParent = container.data[RENDER_PARENT];
const views = container.data[VIEWS]; const views = container.data[VIEWS];
const index = views.indexOf(parent as LViewNode); const index = views.indexOf(currentView);
const beforeNode = const beforeNode = index + 1 < views.length ?
index + 1 < views.length ? (getChildLNode(views[index + 1]) !).native : container.native; (getChildLNode(views[index + 1][HOST_NODE]) !).native :
container.native;
nativeInsertBefore(renderer, renderParent !.native, child, beforeNode); nativeInsertBefore(renderer, renderParent !.native, child, beforeNode);
} else if (parent.tNode.type === TNodeType.ElementContainer) { } else if (parent.tNode.type === TNodeType.ElementContainer) {
const beforeNode = parent.native; const beforeNode = parent.native;
@ -717,8 +713,7 @@ export function appendProjectedNode(
lContainer[RENDER_PARENT] = renderParent; lContainer[RENDER_PARENT] = renderParent;
const views = lContainer[VIEWS]; const views = lContainer[VIEWS];
for (let i = 0; i < views.length; i++) { for (let i = 0; i < views.length; i++) {
const viewNode = views[i]; addRemoveViewFromContainer(node as LContainerNode, views[i], true, node.native);
addRemoveViewFromContainer(node as LContainerNode, viewNode.data, true, node.native);
} }
} else if (node.tNode.type === TNodeType.ElementContainer) { } else if (node.tNode.type === TNodeType.ElementContainer) {
let ngContainerChild = getChildLNode(node as LElementContainerNode); let ngContainerChild = getChildLNode(node as LElementContainerNode);