refactor(ivy): createNodeAtIndex links TNodes on first pass only (#30453)

PR Close #30453
This commit is contained in:
Misko Hevery 2019-05-15 21:08:31 -07:00 committed by Jason Aden
parent 5c5cee9f39
commit 01cf04c85f
1 changed files with 19 additions and 11 deletions

View File

@ -253,10 +253,9 @@ export function createNodeAtIndex(
const lView = getLView();
const tView = lView[TVIEW];
const adjustedIndex = index + HEADER_OFFSET;
const previousOrParentTNode = getPreviousOrParentTNode();
let tNode = tView.data[adjustedIndex] as TNode;
if (tNode == null) {
const previousOrParentTNode = getPreviousOrParentTNode();
const isParent = getIsParent();
const 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
* 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
* 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.
@ -811,7 +811,8 @@ export function elementPropertyInternal<T>(
savePropertyDebugData(tNode, lView, propName, lView[TVIEW].data, nativeOnly);
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.
value = sanitizer != null ? (sanitizer(value, tNode.tagName || '', propName) as any) : value;
if (isProceduralRenderer(renderer)) {
@ -957,7 +958,8 @@ export function instantiateRootComponent<T>(
function resolveDirectives(
tView: TView, viewData: LView, directives: DirectiveDef<any>[] | null, tNode: TNode,
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');
const exportsMap: ({[key: string]: number} | null) = localRefs ? {'': -1} : null;
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.
*/
function refreshDynamicEmbeddedViews(lView: LView) {
@ -1394,7 +1397,8 @@ function refreshDynamicEmbeddedViews(lView: LView) {
if (current[ACTIVE_INDEX] === -1 && isLContainer(current)) {
for (let i = CONTAINER_HEADER_OFFSET; i < current.length; 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');
renderEmbeddedTemplate(dynamicViewData, dynamicViewData[TVIEW], dynamicViewData[CONTEXT] !);
}
@ -1471,9 +1475,12 @@ function syncViewWithBlueprint(componentView: LView) {
* @returns The state passed in
*/
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
// 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
// TODO(benlesh/misko): This implementation is incorrect, because it always adds the LContainer
// to
// 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.
if (lView[CHILD_HEAD]) {
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) {
const hostTView = hostView[TVIEW];
const oldView = enterView(hostView, hostView[T_HOST]);