refactor(ivy): createNodeAtIndex links TNodes on first pass only (#30453)
PR Close #30453
This commit is contained in:
parent
5c5cee9f39
commit
01cf04c85f
|
@ -253,10 +253,9 @@ export function createNodeAtIndex(
|
||||||
const lView = getLView();
|
const lView = getLView();
|
||||||
const tView = lView[TVIEW];
|
const tView = lView[TVIEW];
|
||||||
const adjustedIndex = index + HEADER_OFFSET;
|
const adjustedIndex = index + HEADER_OFFSET;
|
||||||
|
|
||||||
const previousOrParentTNode = getPreviousOrParentTNode();
|
|
||||||
let tNode = tView.data[adjustedIndex] as TNode;
|
let tNode = tView.data[adjustedIndex] as TNode;
|
||||||
if (tNode == null) {
|
if (tNode == null) {
|
||||||
|
const previousOrParentTNode = getPreviousOrParentTNode();
|
||||||
const isParent = getIsParent();
|
const isParent = getIsParent();
|
||||||
const parent =
|
const parent =
|
||||||
isParent ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent;
|
isParent ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent;
|
||||||
|
@ -369,7 +368,8 @@ export function createEmbeddedViewAndNode<T>(
|
||||||
*
|
*
|
||||||
* Dynamically created views must store/retrieve their TViews differently from component views
|
* Dynamically created views must store/retrieve their TViews differently from component views
|
||||||
* because their template functions are nested in the template functions of their hosts, creating
|
* because their template functions are nested in the template functions of their hosts, creating
|
||||||
* closures. If their host template happens to be an embedded template in a loop (e.g. ngFor inside
|
* closures. If their host template happens to be an embedded template in a loop (e.g. ngFor
|
||||||
|
* inside
|
||||||
* an ngFor), the nesting would mean we'd have multiple instances of the template function, so we
|
* an ngFor), the nesting would mean we'd have multiple instances of the template function, so we
|
||||||
* can't store TViews in the template function itself (as we do for comps). Instead, we store the
|
* can't store TViews in the template function itself (as we do for comps). Instead, we store the
|
||||||
* 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.
|
||||||
|
@ -811,7 +811,8 @@ export function elementPropertyInternal<T>(
|
||||||
savePropertyDebugData(tNode, lView, propName, lView[TVIEW].data, nativeOnly);
|
savePropertyDebugData(tNode, lView, propName, lView[TVIEW].data, nativeOnly);
|
||||||
|
|
||||||
const renderer = loadRendererFn ? loadRendererFn(tNode, lView) : lView[RENDERER];
|
const renderer = loadRendererFn ? loadRendererFn(tNode, lView) : lView[RENDERER];
|
||||||
// It is assumed that the sanitizer is only added when the compiler determines that the property
|
// It is assumed that the sanitizer is only added when the compiler determines that the
|
||||||
|
// property
|
||||||
// is risky, so sanitization can be done without further checks.
|
// is risky, so sanitization can be done without further checks.
|
||||||
value = sanitizer != null ? (sanitizer(value, tNode.tagName || '', propName) as any) : value;
|
value = sanitizer != null ? (sanitizer(value, tNode.tagName || '', propName) as any) : value;
|
||||||
if (isProceduralRenderer(renderer)) {
|
if (isProceduralRenderer(renderer)) {
|
||||||
|
@ -957,7 +958,8 @@ export function instantiateRootComponent<T>(
|
||||||
function resolveDirectives(
|
function resolveDirectives(
|
||||||
tView: TView, viewData: LView, directives: DirectiveDef<any>[] | null, tNode: TNode,
|
tView: TView, viewData: LView, directives: DirectiveDef<any>[] | null, tNode: TNode,
|
||||||
localRefs: string[] | null): void {
|
localRefs: string[] | null): void {
|
||||||
// Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in tsickle.
|
// Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in
|
||||||
|
// tsickle.
|
||||||
ngDevMode && assertEqual(tView.firstTemplatePass, true, 'should run on first template pass only');
|
ngDevMode && assertEqual(tView.firstTemplatePass, true, 'should run on first template pass only');
|
||||||
const exportsMap: ({[key: string]: number} | null) = localRefs ? {'': -1} : null;
|
const exportsMap: ({[key: string]: number} | null) = localRefs ? {'': -1} : null;
|
||||||
if (directives) {
|
if (directives) {
|
||||||
|
@ -1383,7 +1385,8 @@ export function createLContainer(
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Goes over dynamic embedded views (ones created through ViewContainerRef APIs) and refreshes them
|
* Goes over dynamic embedded views (ones created through ViewContainerRef APIs) and refreshes
|
||||||
|
* them
|
||||||
* by executing an associated template function.
|
* by executing an associated template function.
|
||||||
*/
|
*/
|
||||||
function refreshDynamicEmbeddedViews(lView: LView) {
|
function refreshDynamicEmbeddedViews(lView: LView) {
|
||||||
|
@ -1394,7 +1397,8 @@ function refreshDynamicEmbeddedViews(lView: LView) {
|
||||||
if (current[ACTIVE_INDEX] === -1 && isLContainer(current)) {
|
if (current[ACTIVE_INDEX] === -1 && isLContainer(current)) {
|
||||||
for (let i = CONTAINER_HEADER_OFFSET; i < current.length; i++) {
|
for (let i = CONTAINER_HEADER_OFFSET; i < current.length; i++) {
|
||||||
const dynamicViewData = current[i];
|
const dynamicViewData = current[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.
|
||||||
ngDevMode && assertDefined(dynamicViewData[TVIEW], 'TView must be allocated');
|
ngDevMode && assertDefined(dynamicViewData[TVIEW], 'TView must be allocated');
|
||||||
renderEmbeddedTemplate(dynamicViewData, dynamicViewData[TVIEW], dynamicViewData[CONTEXT] !);
|
renderEmbeddedTemplate(dynamicViewData, dynamicViewData[TVIEW], dynamicViewData[CONTEXT] !);
|
||||||
}
|
}
|
||||||
|
@ -1471,9 +1475,12 @@ function syncViewWithBlueprint(componentView: LView) {
|
||||||
* @returns The state passed in
|
* @returns The state passed in
|
||||||
*/
|
*/
|
||||||
export function addToViewTree<T extends LView|LContainer>(lView: LView, lViewOrLContainer: T): T {
|
export function addToViewTree<T extends LView|LContainer>(lView: LView, lViewOrLContainer: T): T {
|
||||||
// TODO(benlesh/misko): This implementation is incorrect, because it always adds the LContainer to
|
// TODO(benlesh/misko): This implementation is incorrect, because it always adds the LContainer
|
||||||
// the end of the queue, which means if the developer retrieves the LContainers from RNodes out of
|
// to
|
||||||
// order, the change detection will run out of order, as the act of retrieving the the LContainer
|
// the end of the queue, which means if the developer retrieves the LContainers from RNodes out
|
||||||
|
// of
|
||||||
|
// order, the change detection will run out of order, as the act of retrieving the the
|
||||||
|
// LContainer
|
||||||
// from the RNode is what adds it to the queue.
|
// from the RNode is what adds it to the queue.
|
||||||
if (lView[CHILD_HEAD]) {
|
if (lView[CHILD_HEAD]) {
|
||||||
lView[CHILD_TAIL] ![NEXT] = lViewOrLContainer;
|
lView[CHILD_TAIL] ![NEXT] = lViewOrLContainer;
|
||||||
|
@ -1626,7 +1633,8 @@ export function checkNoChangesInRootView(lView: LView): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */
|
/** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck.
|
||||||
|
*/
|
||||||
export function checkView<T>(hostView: LView, component: T) {
|
export function checkView<T>(hostView: LView, component: T) {
|
||||||
const hostTView = hostView[TVIEW];
|
const hostTView = hostView[TVIEW];
|
||||||
const oldView = enterView(hostView, hostView[T_HOST]);
|
const oldView = enterView(hostView, hostView[T_HOST]);
|
||||||
|
|
Loading…
Reference in New Issue