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
|
// 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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue