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
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<T> extends viewEngine_ComponentFactory<T> {
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<T> extends viewEngine_ComponentFactory<T> {
}
// 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();

View File

@ -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<T> extends viewEngine_TemplateRef<T> {
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;

View File

@ -606,26 +606,25 @@ export function createEmbeddedViewNode<T>(
* TView for dynamically created views on their host TNode, which only has one instance.
*/
export function renderEmbeddedTemplate<T>(
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<T>(
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);
}
/**

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
* are no longer required.
*/
[VIEWS]: LViewNode[];
[VIEWS]: LViewData[];
/**
* 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) {
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);