fix(ivy): properly find RNode (#23193)
As we no longer create native (RNode) comment nodes for containers, we need to execute logic for finding a next sibiling node with RNode when inserting a view. The mentioned logic need to be updated for the case of dynamically created containers (LContainerNode). Indeed, we need to be able to descend into dynamically inserted views while looking for a RNode. To achieve this we need to have a pointer from a host LNode to a dynamically created LContainerNode). PR Close #23193
This commit is contained in:

committed by
Igor Minar

parent
5cd36c7764
commit
d80e9304c6
@ -556,10 +556,12 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainer
|
||||
|
||||
ngDevMode && assertNodeOfPossibleTypes(vcRefHost, LNodeType.Container, LNodeType.Element);
|
||||
|
||||
const lContainer = createLContainer(vcRefHost.parent !, vcRefHost.view, undefined, vcRefHost);
|
||||
const lContainer = createLContainer(vcRefHost.parent !, vcRefHost.view);
|
||||
const lContainerNode: LContainerNode = createLNodeObject(
|
||||
LNodeType.Container, vcRefHost.view, vcRefHost.parent !, undefined, lContainer, null);
|
||||
|
||||
vcRefHost.dynamicLContainerNode = lContainerNode;
|
||||
|
||||
addToViewTree(vcRefHost.view, lContainer);
|
||||
|
||||
di.viewContainerRef = new ViewContainerRef(lContainerNode);
|
||||
@ -608,6 +610,10 @@ class ViewContainerRef implements viewEngine_ViewContainerRef {
|
||||
const adjustedIdx = this._adjustAndAssertIndex(index);
|
||||
|
||||
insertView(this._lContainerNode, lViewNode, adjustedIdx);
|
||||
// invalidate cache of next sibling RNode (we do similar operation in the containerRefreshEnd
|
||||
// instruction)
|
||||
this._lContainerNode.native = undefined;
|
||||
|
||||
this._viewRefs.splice(adjustedIdx, 0, viewRef);
|
||||
|
||||
(lViewNode as{parent: LNode}).parent = this._lContainerNode;
|
||||
|
@ -318,7 +318,8 @@ export function createLNodeObject(
|
||||
data: state,
|
||||
queries: queries,
|
||||
tNode: null,
|
||||
pNextOrParent: null
|
||||
pNextOrParent: null,
|
||||
dynamicLContainerNode: null
|
||||
};
|
||||
}
|
||||
|
||||
@ -386,6 +387,9 @@ export function createLNode(
|
||||
previousOrParentNode.next,
|
||||
`previousOrParentNode's next property should not have been set ${index}.`);
|
||||
previousOrParentNode.next = node;
|
||||
if (previousOrParentNode.dynamicLContainerNode) {
|
||||
previousOrParentNode.dynamicLContainerNode.next = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
previousOrParentNode = node;
|
||||
@ -452,9 +456,10 @@ export function renderEmbeddedTemplate<T>(
|
||||
const directives = currentView && currentView.tView.directiveRegistry;
|
||||
const pipes = currentView && currentView.tView.pipeRegistry;
|
||||
|
||||
const view = createLView(
|
||||
-1, renderer, createTView(directives, pipes), template, context, LViewFlags.CheckAlways);
|
||||
viewNode = createLNode(null, LNodeType.View, null, view);
|
||||
const tView = getOrCreateTView(template, directives, pipes);
|
||||
const lView = createLView(-1, renderer, tView, template, context, LViewFlags.CheckAlways);
|
||||
|
||||
viewNode = createLNode(null, LNodeType.View, null, lView);
|
||||
cm = true;
|
||||
}
|
||||
oldView = enterView(viewNode.data, viewNode);
|
||||
@ -1311,8 +1316,7 @@ function generateInitialInputs(
|
||||
|
||||
|
||||
export function createLContainer(
|
||||
parentLNode: LNode, currentView: LView, template?: ComponentTemplate<any>,
|
||||
host?: LContainerNode | LElementNode): LContainer {
|
||||
parentLNode: LNode, currentView: LView, template?: ComponentTemplate<any>): LContainer {
|
||||
ngDevMode && assertNotNull(parentLNode, 'containers should have a parent');
|
||||
return <LContainer>{
|
||||
views: [],
|
||||
@ -1324,8 +1328,7 @@ export function createLContainer(
|
||||
next: null,
|
||||
parent: currentView,
|
||||
dynamicViewCount: 0,
|
||||
queries: null,
|
||||
host: host == null ? null : host
|
||||
queries: null
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -80,13 +80,6 @@ export interface LContainer {
|
||||
* this container are reported to queries referenced here.
|
||||
*/
|
||||
queries: LQueries|null;
|
||||
|
||||
/**
|
||||
* If a LContainer is created dynamically (by a directive requesting ViewContainerRef) this fields
|
||||
* keeps a reference to a node on which a ViewContainerRef was requested. We need to store this
|
||||
* information to find a next render sibling node.
|
||||
*/
|
||||
host: LContainerNode|LElementNode|null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,6 +130,11 @@ export interface LNode {
|
||||
* data about this node.
|
||||
*/
|
||||
tNode: TNode|null;
|
||||
|
||||
/**
|
||||
* A pointer to a LContainerNode created by directives requesting ViewContainerRef
|
||||
*/
|
||||
dynamicLContainerNode: LContainerNode|null;
|
||||
}
|
||||
|
||||
|
||||
@ -158,6 +163,7 @@ export interface LTextNode extends LNode {
|
||||
/** LTextNodes can be inside LElementNodes or inside LViewNodes. */
|
||||
readonly parent: LElementNode|LViewNode;
|
||||
readonly data: null;
|
||||
dynamicLContainerNode: null;
|
||||
}
|
||||
|
||||
/** Abstract node which contains root nodes of a view. */
|
||||
@ -169,6 +175,7 @@ export interface LViewNode extends LNode {
|
||||
/** LViewNodes can only be added to LContainerNodes. */
|
||||
readonly parent: LContainerNode|null;
|
||||
readonly data: LView;
|
||||
dynamicLContainerNode: null;
|
||||
}
|
||||
|
||||
/** Abstract node container which contains other views. */
|
||||
@ -199,6 +206,7 @@ export interface LProjectionNode extends LNode {
|
||||
|
||||
/** Projections can be added to elements or views. */
|
||||
readonly parent: LElementNode|LViewNode;
|
||||
dynamicLContainerNode: null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,8 +125,10 @@ function findFirstRNode(rootNode: LNode): RElement|RText|null {
|
||||
// A LElementNode has a matching RNode in LElementNode.native
|
||||
return (node as LElementNode).native;
|
||||
} else if (node.type === LNodeType.Container) {
|
||||
// For container look at the first node of the view next
|
||||
const childContainerData: LContainer = (node as LContainerNode).data;
|
||||
const lContainerNode: LContainerNode = (node as LContainerNode);
|
||||
const childContainerData: LContainer = lContainerNode.dynamicLContainerNode ?
|
||||
lContainerNode.dynamicLContainerNode.data :
|
||||
lContainerNode.data;
|
||||
nextNode = childContainerData.views.length ? childContainerData.views[0].child : null;
|
||||
} else if (node.type === LNodeType.Projection) {
|
||||
// For Projection look at the first projected node
|
||||
@ -281,10 +283,7 @@ export function insertView(
|
||||
if (!beforeNode) {
|
||||
let containerNextNativeNode = container.native;
|
||||
if (containerNextNativeNode === undefined) {
|
||||
// TODO(pk): this is probably too simplistic, add more tests for various host placements
|
||||
// (dynamic view, projection, ...)
|
||||
containerNextNativeNode = container.native =
|
||||
findNextRNodeSibling(container.data.host ? container.data.host : container, null);
|
||||
containerNextNativeNode = container.native = findNextRNodeSibling(container, null);
|
||||
}
|
||||
beforeNode = containerNextNativeNode;
|
||||
}
|
||||
|
Reference in New Issue
Block a user