refactor(ivy): LContainers should store views not nodes (#25933)
PR Close #25933
This commit is contained in:
parent
a09c3923db
commit
47f4412650
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue