refactor(ivy): add tNodes for view nodes and hosts (#24113)
PR Close #24113
This commit is contained in:
parent
13cb75da8b
commit
8216657681
|
@ -187,7 +187,7 @@ export function LifecycleHooksFeature(component: any, def: ComponentDef<any>): v
|
||||||
|
|
||||||
// Root component is always created at dir index 0
|
// Root component is always created at dir index 0
|
||||||
queueInitHooks(0, def.onInit, def.doCheck, elementNode.view.tView);
|
queueInitHooks(0, def.onInit, def.doCheck, elementNode.view.tView);
|
||||||
queueLifecycleHooks(elementNode.tNode !.flags, elementNode.view);
|
queueLifecycleHooks(elementNode.tNode.flags, elementNode.view);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_Vie
|
||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
|
|
||||||
import {assertGreaterThan, assertLessThan, assertNotNull} from './assert';
|
import {assertGreaterThan, assertLessThan, assertNotNull} from './assert';
|
||||||
import {addToViewTree, assertPreviousIsParent, createLContainer, createLNodeObject, createTView, getDirectiveInstance, getPreviousOrParentNode, getRenderer, isComponent, renderEmbeddedTemplate, resolveDirective} from './instructions';
|
import {addToViewTree, assertPreviousIsParent, createLContainer, createLNodeObject, createTNode, createTView, getDirectiveInstance, getPreviousOrParentNode, getRenderer, isComponent, renderEmbeddedTemplate, resolveDirective} from './instructions';
|
||||||
import {ComponentTemplate, DirectiveDef, DirectiveDefList, PipeDefList} from './interfaces/definition';
|
import {ComponentTemplate, DirectiveDef, DirectiveDefList, PipeDefList} from './interfaces/definition';
|
||||||
import {LInjector} from './interfaces/injector';
|
import {LInjector} from './interfaces/injector';
|
||||||
import {LContainerNode, LElementNode, LNode, LNodeType, LViewNode, TNodeFlags} from './interfaces/node';
|
import {LContainerNode, LElementNode, LNode, LNodeType, LViewNode, TNodeFlags} from './interfaces/node';
|
||||||
|
@ -254,7 +254,7 @@ export function injectAttribute(attrName: string): string|undefined {
|
||||||
ngDevMode && assertPreviousIsParent();
|
ngDevMode && assertPreviousIsParent();
|
||||||
const lElement = getPreviousOrParentNode() as LElementNode;
|
const lElement = getPreviousOrParentNode() as LElementNode;
|
||||||
ngDevMode && assertNodeType(lElement, LNodeType.Element);
|
ngDevMode && assertNodeType(lElement, LNodeType.Element);
|
||||||
const tElement = lElement.tNode !;
|
const tElement = lElement.tNode;
|
||||||
ngDevMode && assertNotNull(tElement, 'expecting tNode');
|
ngDevMode && assertNotNull(tElement, 'expecting tNode');
|
||||||
const attrs = tElement.attrs;
|
const attrs = tElement.attrs;
|
||||||
if (attrs) {
|
if (attrs) {
|
||||||
|
@ -278,7 +278,7 @@ export function getOrCreateChangeDetectorRef(
|
||||||
if (di.changeDetectorRef) return di.changeDetectorRef;
|
if (di.changeDetectorRef) return di.changeDetectorRef;
|
||||||
|
|
||||||
const currentNode = di.node;
|
const currentNode = di.node;
|
||||||
if (isComponent(currentNode.tNode !)) {
|
if (isComponent(currentNode.tNode)) {
|
||||||
return di.changeDetectorRef = createViewRef(currentNode.data as LView, context);
|
return di.changeDetectorRef = createViewRef(currentNode.data as LView, context);
|
||||||
} else if (currentNode.type === LNodeType.Element) {
|
} else if (currentNode.type === LNodeType.Element) {
|
||||||
return di.changeDetectorRef = getOrCreateHostChangeDetector(currentNode.view.node);
|
return di.changeDetectorRef = getOrCreateHostChangeDetector(currentNode.view.node);
|
||||||
|
@ -298,7 +298,7 @@ function getOrCreateHostChangeDetector(currentNode: LViewNode | LElementNode):
|
||||||
createViewRef(
|
createViewRef(
|
||||||
hostNode.data as LView,
|
hostNode.data as LView,
|
||||||
hostNode.view
|
hostNode.view
|
||||||
.directives ![hostNode.tNode !.flags >> TNodeFlags.DirectiveStartingIndexShift]);
|
.directives ![hostNode.tNode.flags >> TNodeFlags.DirectiveStartingIndexShift]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -361,7 +361,7 @@ export function getOrCreateInjectable<T>(
|
||||||
// At this point, we have an injector which *may* contain the token, so we step through the
|
// At this point, we have an injector which *may* contain the token, so we step through the
|
||||||
// directives associated with the injector's corresponding node to get the directive instance.
|
// directives associated with the injector's corresponding node to get the directive instance.
|
||||||
const node = injector.node;
|
const node = injector.node;
|
||||||
const nodeFlags = node.tNode !.flags;
|
const nodeFlags = node.tNode.flags;
|
||||||
const count = nodeFlags & TNodeFlags.DirectiveCountMask;
|
const count = nodeFlags & TNodeFlags.DirectiveCountMask;
|
||||||
|
|
||||||
if (count !== 0) {
|
if (count !== 0) {
|
||||||
|
@ -572,8 +572,12 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainer
|
||||||
const lContainerNode: LContainerNode = createLNodeObject(
|
const lContainerNode: LContainerNode = createLNodeObject(
|
||||||
LNodeType.Container, vcRefHost.view, vcRefHost.parent !, undefined, lContainer, null);
|
LNodeType.Container, vcRefHost.view, vcRefHost.parent !, undefined, lContainer, null);
|
||||||
|
|
||||||
// TODO(kara): Separate into own TNode when moving parent/child properties
|
const hostTNode = vcRefHost.tNode;
|
||||||
lContainerNode.tNode = vcRefHost.tNode;
|
if (!hostTNode.dynamicContainerNode) {
|
||||||
|
hostTNode.dynamicContainerNode = createTNode(hostTNode.index, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
lContainerNode.tNode = hostTNode.dynamicContainerNode;
|
||||||
vcRefHost.dynamicLContainerNode = lContainerNode;
|
vcRefHost.dynamicLContainerNode = lContainerNode;
|
||||||
|
|
||||||
addToViewTree(vcRefHost.view, lContainer);
|
addToViewTree(vcRefHost.view, lContainer);
|
||||||
|
@ -699,7 +703,7 @@ export function getOrCreateTemplateRef<T>(di: LInjector): viewEngine_TemplateRef
|
||||||
if (!di.templateRef) {
|
if (!di.templateRef) {
|
||||||
ngDevMode && assertNodeType(di.node, LNodeType.Container);
|
ngDevMode && assertNodeType(di.node, LNodeType.Container);
|
||||||
const hostNode = di.node as LContainerNode;
|
const hostNode = di.node as LContainerNode;
|
||||||
const hostTNode = hostNode.tNode !;
|
const hostTNode = hostNode.tNode;
|
||||||
const hostTView = hostNode.view.tView;
|
const hostTView = hostNode.view.tView;
|
||||||
if (!hostTNode.tViews) {
|
if (!hostTNode.tViews) {
|
||||||
hostTNode.tViews = createTView(hostTView.directiveRegistry, hostTView.pipeRegistry);
|
hostTNode.tViews = createTView(hostTView.directiveRegistry, hostTView.pipeRegistry);
|
||||||
|
|
|
@ -349,7 +349,7 @@ export function createLNodeObject(
|
||||||
nodeInjector: parent ? parent.nodeInjector : null,
|
nodeInjector: parent ? parent.nodeInjector : null,
|
||||||
data: state,
|
data: state,
|
||||||
queries: queries,
|
queries: queries,
|
||||||
tNode: null,
|
tNode: null !,
|
||||||
pNextOrParent: null,
|
pNextOrParent: null,
|
||||||
dynamicLContainerNode: null
|
dynamicLContainerNode: null
|
||||||
};
|
};
|
||||||
|
@ -371,7 +371,7 @@ export function createLNode(
|
||||||
index: number | null, type: LNodeType.Element, native: RElement | RText | null,
|
index: number | null, type: LNodeType.Element, native: RElement | RText | null,
|
||||||
name: string | null, attrs: string[] | null, lView?: LView | null): LElementNode;
|
name: string | null, attrs: string[] | null, lView?: LView | null): LElementNode;
|
||||||
export function createLNode(
|
export function createLNode(
|
||||||
index: null, type: LNodeType.View, native: null, name: null, attrs: null,
|
index: number | null, type: LNodeType.View, native: null, name: null, attrs: null,
|
||||||
lView: LView): LViewNode;
|
lView: LView): LViewNode;
|
||||||
export function createLNode(
|
export function createLNode(
|
||||||
index: number, type: LNodeType.Container, native: undefined, name: string | null,
|
index: number, type: LNodeType.Container, native: undefined, name: string | null,
|
||||||
|
@ -392,14 +392,12 @@ export function createLNode(
|
||||||
const node =
|
const node =
|
||||||
createLNodeObject(type, currentView, parent, native, isState ? state as any : null, queries);
|
createLNodeObject(type, currentView, parent, native, isState ? state as any : null, queries);
|
||||||
|
|
||||||
if ((type & LNodeType.ViewOrElement) === LNodeType.ViewOrElement && isState) {
|
if (index === null || type === LNodeType.View) {
|
||||||
// Bit of a hack to bust through the readonly because there is a circular dep between
|
// View nodes are not stored in data because they can be added / removed at runtime (which
|
||||||
// LView and LNode.
|
// would cause indices to change). Their TNodes are instead stored in TView.node.
|
||||||
ngDevMode && assertNull((state as LView).node, 'LView.node should not have been initialized');
|
node.tNode = (state as LView).tView.node || createTNode(index, null, null, null);
|
||||||
(state as LView as{node: LNode}).node = node;
|
} else {
|
||||||
}
|
// This is an element or container or projection node
|
||||||
if (index != null) {
|
|
||||||
// We are Element or Container
|
|
||||||
ngDevMode && assertDataNext(index);
|
ngDevMode && assertDataNext(index);
|
||||||
data[index] = node;
|
data[index] = node;
|
||||||
|
|
||||||
|
@ -407,7 +405,9 @@ export function createLNode(
|
||||||
if (index >= tData.length) {
|
if (index >= tData.length) {
|
||||||
const tNode = tData[index] = createTNode(index, name, attrs, null);
|
const tNode = tData[index] = createTNode(index, name, attrs, null);
|
||||||
if (!isParent && previousOrParentNode) {
|
if (!isParent && previousOrParentNode) {
|
||||||
previousOrParentNode.tNode !.next = tNode;
|
const previousTNode = previousOrParentNode.tNode;
|
||||||
|
previousTNode.next = tNode;
|
||||||
|
if (previousTNode.dynamicContainerNode) previousTNode.dynamicContainerNode.next = tNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.tNode = tData[index] as TNode;
|
node.tNode = tData[index] as TNode;
|
||||||
|
@ -427,6 +427,16 @@ export function createLNode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// View nodes and host elements need to set their host node (components set host nodes later)
|
||||||
|
if ((type & LNodeType.ViewOrElement) === LNodeType.ViewOrElement && isState) {
|
||||||
|
// Bit of a hack to bust through the readonly because there is a circular dep between
|
||||||
|
// LView and LNode.
|
||||||
|
ngDevMode && assertNull((state as LView).node, 'LView.node should not have been initialized');
|
||||||
|
(state as{node: LNode}).node = node;
|
||||||
|
if (firstTemplatePass) (state as LView).tView.node = node.tNode;
|
||||||
|
}
|
||||||
|
|
||||||
previousOrParentNode = node;
|
previousOrParentNode = node;
|
||||||
isParent = true;
|
isParent = true;
|
||||||
return node;
|
return node;
|
||||||
|
@ -613,7 +623,7 @@ function createDirectivesAndLocals(
|
||||||
const node = previousOrParentNode;
|
const node = previousOrParentNode;
|
||||||
if (firstTemplatePass) {
|
if (firstTemplatePass) {
|
||||||
ngDevMode && ngDevMode.firstTemplatePass++;
|
ngDevMode && ngDevMode.firstTemplatePass++;
|
||||||
cacheMatchingDirectivesForNode(node.tNode !, currentView.tView, localRefs || null);
|
cacheMatchingDirectivesForNode(node.tNode, currentView.tView, localRefs || null);
|
||||||
} else {
|
} else {
|
||||||
instantiateDirectivesDirectly();
|
instantiateDirectivesDirectly();
|
||||||
}
|
}
|
||||||
|
@ -708,7 +718,7 @@ export function isComponent(tNode: TNode): boolean {
|
||||||
* This function instantiates the given directives.
|
* This function instantiates the given directives.
|
||||||
*/
|
*/
|
||||||
function instantiateDirectivesDirectly() {
|
function instantiateDirectivesDirectly() {
|
||||||
const tNode = previousOrParentNode.tNode !;
|
const tNode = previousOrParentNode.tNode;
|
||||||
const count = tNode.flags & TNodeFlags.DirectiveCountMask;
|
const count = tNode.flags & TNodeFlags.DirectiveCountMask;
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
|
@ -758,7 +768,7 @@ function saveNameToExportMap(
|
||||||
* to data[] in the same order as they are loaded in the template with load().
|
* to data[] in the same order as they are loaded in the template with load().
|
||||||
*/
|
*/
|
||||||
function saveResolvedLocalsInData(): void {
|
function saveResolvedLocalsInData(): void {
|
||||||
const localNames = previousOrParentNode.tNode !.localNames;
|
const localNames = previousOrParentNode.tNode.localNames;
|
||||||
if (localNames) {
|
if (localNames) {
|
||||||
for (let i = 0; i < localNames.length; i += 2) {
|
for (let i = 0; i < localNames.length; i += 2) {
|
||||||
const index = localNames[i + 1] as number;
|
const index = localNames[i + 1] as number;
|
||||||
|
@ -796,6 +806,7 @@ export function createTView(
|
||||||
defs: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null): TView {
|
defs: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null): TView {
|
||||||
ngDevMode && ngDevMode.tView++;
|
ngDevMode && ngDevMode.tView++;
|
||||||
return {
|
return {
|
||||||
|
node: null !,
|
||||||
data: [],
|
data: [],
|
||||||
directives: null,
|
directives: null,
|
||||||
firstTemplatePass: true,
|
firstTemplatePass: true,
|
||||||
|
@ -879,7 +890,7 @@ export function hostElement(
|
||||||
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer));
|
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer));
|
||||||
|
|
||||||
if (firstTemplatePass) {
|
if (firstTemplatePass) {
|
||||||
node.tNode !.flags = TNodeFlags.isComponent;
|
node.tNode.flags = TNodeFlags.isComponent;
|
||||||
if (def.diPublic) def.diPublic(def);
|
if (def.diPublic) def.diPublic(def);
|
||||||
currentView.tView.directives = [def];
|
currentView.tView.directives = [def];
|
||||||
}
|
}
|
||||||
|
@ -918,11 +929,11 @@ export function listener(
|
||||||
cleanupFns.push(eventName, native, wrappedListener, useCapture);
|
cleanupFns.push(eventName, native, wrappedListener, useCapture);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tNode: TNode|null = node.tNode !;
|
let tNode: TNode|null = node.tNode;
|
||||||
if (tNode.outputs === undefined) {
|
if (tNode.outputs === undefined) {
|
||||||
// if we create TNode here, inputs must be undefined so we know they still need to be
|
// if we create TNode here, inputs must be undefined so we know they still need to be
|
||||||
// checked
|
// checked
|
||||||
tNode.outputs = generatePropertyAliases(node.tNode !.flags, BindingDirection.Output);
|
tNode.outputs = generatePropertyAliases(node.tNode.flags, BindingDirection.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
const outputs = tNode.outputs;
|
const outputs = tNode.outputs;
|
||||||
|
@ -955,7 +966,7 @@ export function elementEnd() {
|
||||||
ngDevMode && assertNodeType(previousOrParentNode, LNodeType.Element);
|
ngDevMode && assertNodeType(previousOrParentNode, LNodeType.Element);
|
||||||
const queries = previousOrParentNode.queries;
|
const queries = previousOrParentNode.queries;
|
||||||
queries && queries.addNode(previousOrParentNode);
|
queries && queries.addNode(previousOrParentNode);
|
||||||
queueLifecycleHooks(previousOrParentNode.tNode !.flags, currentView);
|
queueLifecycleHooks(previousOrParentNode.tNode.flags, currentView);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1002,12 +1013,12 @@ export function elementProperty<T>(
|
||||||
index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn): void {
|
index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn): void {
|
||||||
if (value === NO_CHANGE) return;
|
if (value === NO_CHANGE) return;
|
||||||
const node = data[index] as LElementNode;
|
const node = data[index] as LElementNode;
|
||||||
const tNode = node.tNode !;
|
const tNode = node.tNode;
|
||||||
// if tNode.inputs is undefined, a listener has created outputs, but inputs haven't
|
// if tNode.inputs is undefined, a listener has created outputs, but inputs haven't
|
||||||
// yet been checked
|
// yet been checked
|
||||||
if (tNode && tNode.inputs === undefined) {
|
if (tNode && tNode.inputs === undefined) {
|
||||||
// mark inputs as checked
|
// mark inputs as checked
|
||||||
tNode.inputs = generatePropertyAliases(node.tNode !.flags, BindingDirection.Input);
|
tNode.inputs = generatePropertyAliases(node.tNode.flags, BindingDirection.Input);
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputData = tNode && tNode.inputs;
|
const inputData = tNode && tNode.inputs;
|
||||||
|
@ -1036,8 +1047,9 @@ export function elementProperty<T>(
|
||||||
* @param tViews Any TViews attached to this node
|
* @param tViews Any TViews attached to this node
|
||||||
* @returns the TNode object
|
* @returns the TNode object
|
||||||
*/
|
*/
|
||||||
function createTNode(
|
export function createTNode(
|
||||||
index: number, tagName: string | null, attrs: string[] | null, tViews: TView[] | null): TNode {
|
index: number | null, tagName: string | null, attrs: string[] | null,
|
||||||
|
tViews: TView[] | null): TNode {
|
||||||
ngDevMode && ngDevMode.tNode++;
|
ngDevMode && ngDevMode.tNode++;
|
||||||
return {
|
return {
|
||||||
index: index,
|
index: index,
|
||||||
|
@ -1049,7 +1061,8 @@ function createTNode(
|
||||||
inputs: undefined,
|
inputs: undefined,
|
||||||
outputs: undefined,
|
outputs: undefined,
|
||||||
tViews: tViews,
|
tViews: tViews,
|
||||||
next: null
|
next: null,
|
||||||
|
dynamicContainerNode: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1321,8 +1334,11 @@ function addComponentLogic<T>(index: number, instance: T, def: ComponentDef<T>):
|
||||||
tView, null, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways,
|
tView, null, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways,
|
||||||
getCurrentSanitizer()));
|
getCurrentSanitizer()));
|
||||||
|
|
||||||
(previousOrParentNode.data as any) = hostView;
|
// We need to set the host node/data here because when the component LNode was created,
|
||||||
(hostView.node as any) = previousOrParentNode;
|
// we didn't yet know it was a component (just an element).
|
||||||
|
(previousOrParentNode as{data: LView}).data = hostView;
|
||||||
|
(hostView as{node: LNode}).node = previousOrParentNode;
|
||||||
|
if (firstTemplatePass) tView.node = previousOrParentNode.tNode;
|
||||||
|
|
||||||
initChangeDetectorIfExisting(previousOrParentNode.nodeInjector, instance, hostView);
|
initChangeDetectorIfExisting(previousOrParentNode.nodeInjector, instance, hostView);
|
||||||
|
|
||||||
|
@ -1351,19 +1367,19 @@ export function baseDirectiveCreate<T>(
|
||||||
directives[index] = directive;
|
directives[index] = directive;
|
||||||
|
|
||||||
if (firstTemplatePass) {
|
if (firstTemplatePass) {
|
||||||
const flags = previousOrParentNode.tNode !.flags;
|
const flags = previousOrParentNode.tNode.flags;
|
||||||
if ((flags & TNodeFlags.DirectiveCountMask) === 0) {
|
if ((flags & TNodeFlags.DirectiveCountMask) === 0) {
|
||||||
// When the first directive is created:
|
// When the first directive is created:
|
||||||
// - save the index,
|
// - save the index,
|
||||||
// - set the number of directives to 1
|
// - set the number of directives to 1
|
||||||
previousOrParentNode.tNode !.flags =
|
previousOrParentNode.tNode.flags =
|
||||||
index << TNodeFlags.DirectiveStartingIndexShift | flags & TNodeFlags.isComponent | 1;
|
index << TNodeFlags.DirectiveStartingIndexShift | flags & TNodeFlags.isComponent | 1;
|
||||||
} else {
|
} else {
|
||||||
// Only need to bump the size when subsequent directives are created
|
// Only need to bump the size when subsequent directives are created
|
||||||
ngDevMode && assertNotEqual(
|
ngDevMode && assertNotEqual(
|
||||||
flags & TNodeFlags.DirectiveCountMask, TNodeFlags.DirectiveCountMask,
|
flags & TNodeFlags.DirectiveCountMask, TNodeFlags.DirectiveCountMask,
|
||||||
'Reached the max number of directives');
|
'Reached the max number of directives');
|
||||||
previousOrParentNode.tNode !.flags++;
|
previousOrParentNode.tNode.flags++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const diPublic = directiveDef !.diPublic;
|
const diPublic = directiveDef !.diPublic;
|
||||||
|
@ -1481,7 +1497,7 @@ export function container(
|
||||||
const node = createLNode(
|
const node = createLNode(
|
||||||
index, LNodeType.Container, undefined, tagName || null, attrs || null, lContainer);
|
index, LNodeType.Container, undefined, tagName || null, attrs || null, lContainer);
|
||||||
|
|
||||||
if (firstTemplatePass && template == null) node.tNode !.tViews = [];
|
if (firstTemplatePass && template == null) node.tNode.tViews = [];
|
||||||
|
|
||||||
// Containers are added to the current view tree instead of their embedded views
|
// Containers are added to the current view tree instead of their embedded views
|
||||||
// because views can be removed and re-inserted.
|
// because views can be removed and re-inserted.
|
||||||
|
@ -1618,7 +1634,8 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags {
|
||||||
newView.queries = lContainer.queries.enterView(lContainer.nextIndex);
|
newView.queries = lContainer.queries.enterView(lContainer.nextIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
enterView(newView, viewNode = createLNode(null, LNodeType.View, null, null, null, newView));
|
enterView(
|
||||||
|
newView, viewNode = createLNode(viewBlockId, LNodeType.View, null, null, null, newView));
|
||||||
}
|
}
|
||||||
return getRenderFlags(viewNode.data);
|
return getRenderFlags(viewNode.data);
|
||||||
}
|
}
|
||||||
|
@ -2027,7 +2044,7 @@ export function getRootView(component: any): LView {
|
||||||
export function detectChanges<T>(component: T): void {
|
export function detectChanges<T>(component: T): void {
|
||||||
const hostNode = _getComponentHostLElementNode(component);
|
const hostNode = _getComponentHostLElementNode(component);
|
||||||
ngDevMode && assertNotNull(hostNode.data, 'Component host node should be attached to an LView');
|
ngDevMode && assertNotNull(hostNode.data, 'Component host node should be attached to an LView');
|
||||||
const componentIndex = hostNode.tNode !.flags >> TNodeFlags.DirectiveStartingIndexShift;
|
const componentIndex = hostNode.tNode.flags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||||
const def = hostNode.view.tView.directives ![componentIndex] as ComponentDef<T>;
|
const def = hostNode.view.tView.directives ![componentIndex] as ComponentDef<T>;
|
||||||
detectChangesInternal(hostNode.data as LView, hostNode, def, component);
|
detectChangesInternal(hostNode.data as LView, hostNode, def, component);
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,11 +118,12 @@ export interface LNode {
|
||||||
* Pointer to the corresponding TNode object, which stores static
|
* Pointer to the corresponding TNode object, which stores static
|
||||||
* data about this node.
|
* data about this node.
|
||||||
*/
|
*/
|
||||||
tNode: TNode|null;
|
tNode: TNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pointer to a LContainerNode created by directives requesting ViewContainerRef
|
* A pointer to a LContainerNode created by directives requesting ViewContainerRef
|
||||||
*/
|
*/
|
||||||
|
// TODO(kara): Remove when removing LNodes
|
||||||
dynamicLContainerNode: LContainerNode|null;
|
dynamicLContainerNode: LContainerNode|null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,8 +211,10 @@ export interface TNode {
|
||||||
*
|
*
|
||||||
* This is necessary to get from any TNode to its corresponding LNode when
|
* This is necessary to get from any TNode to its corresponding LNode when
|
||||||
* traversing the node tree.
|
* traversing the node tree.
|
||||||
|
*
|
||||||
|
* If null, this is a view node created from a dynamically created view.
|
||||||
*/
|
*/
|
||||||
index: number;
|
index: number|null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This number stores two values using its bits:
|
* This number stores two values using its bits:
|
||||||
|
@ -306,6 +309,11 @@ export interface TNode {
|
||||||
* to insert them or remove them from the DOM.
|
* to insert them or remove them from the DOM.
|
||||||
*/
|
*/
|
||||||
next: TNode|null;
|
next: TNode|null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pointer to a LContainerNode created by directives requesting ViewContainerRef
|
||||||
|
*/
|
||||||
|
dynamicContainerNode: TNode|null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Static data for an LElementNode */
|
/** Static data for an LElementNode */
|
||||||
|
|
|
@ -46,6 +46,7 @@ export interface LView {
|
||||||
*
|
*
|
||||||
* If `LElementNode`, this is the LView of a component.
|
* If `LElementNode`, this is the LView of a component.
|
||||||
*/
|
*/
|
||||||
|
// TODO(kara): Remove when we have parent/child on TNodes
|
||||||
readonly node: LViewNode|LElementNode;
|
readonly node: LViewNode|LElementNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -241,6 +242,17 @@ export interface LViewOrLContainer {
|
||||||
* Stored on the template function as ngPrivateData.
|
* Stored on the template function as ngPrivateData.
|
||||||
*/
|
*/
|
||||||
export interface TView {
|
export interface TView {
|
||||||
|
/**
|
||||||
|
* Pointer to the `TNode` that represents the root of the view.
|
||||||
|
*
|
||||||
|
* If this is a `TNode` for an `LViewNode`, this is an embedded view of a container.
|
||||||
|
* We need this pointer to be able to efficiently find this node when inserting the view
|
||||||
|
* into an anchor.
|
||||||
|
*
|
||||||
|
* If this is a `TNode` for an `LElementNode`, this is the TView of a component.
|
||||||
|
*/
|
||||||
|
node: TNode;
|
||||||
|
|
||||||
/** Whether or not this template has been processed. */
|
/** Whether or not this template has been processed. */
|
||||||
firstTemplatePass: boolean;
|
firstTemplatePass: boolean;
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ export function getNextLNode(node: LNode): LNode|null {
|
||||||
const lView = node.data as LView;
|
const lView = node.data as LView;
|
||||||
return lView.next ? (lView.next as LView).node : null;
|
return lView.next ? (lView.next as LView).node : null;
|
||||||
}
|
}
|
||||||
return node.tNode !.next ? node.view.data[node.tNode !.next !.index] : null;
|
return node.tNode.next ? node.view.data[node.tNode.next !.index as number] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -195,7 +195,7 @@ function getIdxOfMatchingSelector(tNode: TNode, selector: string): number|null {
|
||||||
*/
|
*/
|
||||||
function getIdxOfMatchingDirective(node: LNode, type: Type<any>): number|null {
|
function getIdxOfMatchingDirective(node: LNode, type: Type<any>): number|null {
|
||||||
const defs = node.view.tView.directives !;
|
const defs = node.view.tView.directives !;
|
||||||
const flags = node.tNode !.flags;
|
const flags = node.tNode.flags;
|
||||||
const count = flags & TNodeFlags.DirectiveCountMask;
|
const count = flags & TNodeFlags.DirectiveCountMask;
|
||||||
const start = flags >> TNodeFlags.DirectiveStartingIndexShift;
|
const start = flags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||||
const end = start + count;
|
const end = start + count;
|
||||||
|
@ -241,8 +241,7 @@ function add(query: LQuery<any>| null, node: LNode) {
|
||||||
} else {
|
} else {
|
||||||
const selector = predicate.selector !;
|
const selector = predicate.selector !;
|
||||||
for (let i = 0; i < selector.length; i++) {
|
for (let i = 0; i < selector.length; i++) {
|
||||||
ngDevMode && assertNotNull(node.tNode, 'node.tNode');
|
const directiveIdx = getIdxOfMatchingSelector(node.tNode, selector[i]);
|
||||||
const directiveIdx = getIdxOfMatchingSelector(node.tNode !, selector[i]);
|
|
||||||
if (directiveIdx !== null) {
|
if (directiveIdx !== null) {
|
||||||
// a node is matching a predicate - determine what to read
|
// a node is matching a predicate - determine what to read
|
||||||
// note that queries using name selector must specify read strategy
|
// note that queries using name selector must specify read strategy
|
||||||
|
|
|
@ -48,7 +48,7 @@ describe('instructions', () => {
|
||||||
expect(t.html).toEqual('<div title="javascript:true"></div>');
|
expect(t.html).toEqual('<div title="javascript:true"></div>');
|
||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 1,
|
firstTemplatePass: 1,
|
||||||
tNode: 1,
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
tView: 1,
|
tView: 1,
|
||||||
rendererCreateElement: 1,
|
rendererCreateElement: 1,
|
||||||
rendererSetAttribute: 2
|
rendererSetAttribute: 2
|
||||||
|
@ -69,7 +69,7 @@ describe('instructions', () => {
|
||||||
expect(t.html).toEqual('<div title="javascript:false"></div>');
|
expect(t.html).toEqual('<div title="javascript:false"></div>');
|
||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 1,
|
firstTemplatePass: 1,
|
||||||
tNode: 1,
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
tView: 1,
|
tView: 1,
|
||||||
rendererCreateElement: 1,
|
rendererCreateElement: 1,
|
||||||
});
|
});
|
||||||
|
@ -83,7 +83,7 @@ describe('instructions', () => {
|
||||||
expect((t.hostNode.native as HTMLElement).querySelector('div') !.hidden).toEqual(false);
|
expect((t.hostNode.native as HTMLElement).querySelector('div') !.hidden).toEqual(false);
|
||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 1,
|
firstTemplatePass: 1,
|
||||||
tNode: 1,
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
tView: 1,
|
tView: 1,
|
||||||
rendererCreateElement: 1,
|
rendererCreateElement: 1,
|
||||||
rendererSetProperty: 1
|
rendererSetProperty: 1
|
||||||
|
|
|
@ -32,7 +32,7 @@ describe('render3 integration test', () => {
|
||||||
}
|
}
|
||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 1,
|
firstTemplatePass: 1,
|
||||||
tNode: 2,
|
tNode: 3, // 1 for div, 1 for text, 1 for host element
|
||||||
tView: 1,
|
tView: 1,
|
||||||
rendererCreateElement: 1,
|
rendererCreateElement: 1,
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,7 +19,8 @@ function testLStaticData(tagName: string, attrs: string[] | null): TNode {
|
||||||
inputs: undefined,
|
inputs: undefined,
|
||||||
outputs: undefined,
|
outputs: undefined,
|
||||||
tViews: null,
|
tViews: null,
|
||||||
next: null
|
next: null,
|
||||||
|
dynamicContainerNode: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue