refactor(core): Remove reliance on `TNodeType.View`. (#38707)

`TNodeType.View` was created to support inline views. That feature did
not materialize and we have since removed the instructions for it, leave
 an unneeded `TNodeType.View` which was still used in a very
 inconsistent way. This change no longer created `TNodeType.View` (and
 there will be a follow up chang to completely remove it.)

Also simplified the mental model so that `LView[HOST]`/`LView[T_HOST]`
always point to the insertion location of the `LView`.

PR Close #38707
This commit is contained in:
Misko Hevery 2020-09-14 11:21:15 -07:00 committed by Alex Rickabaugh
parent b2579d43cd
commit eb32b6bd6b
45 changed files with 372 additions and 377 deletions

View File

@ -389,27 +389,6 @@
"packages/core/src/render3/definition.ts",
"packages/core/src/metadata/ng_module.ts"
],
[
"packages/core/src/application_ref.ts",
"packages/core/src/application_tokens.ts",
"packages/core/src/linker/component_factory.ts",
"packages/core/src/change_detection/change_detection.ts",
"packages/core/src/change_detection/change_detector_ref.ts",
"packages/core/src/render3/view_engine_compatibility.ts",
"packages/core/src/render3/node_manipulation.ts",
"packages/core/src/core.ts",
"packages/core/src/metadata.ts",
"packages/core/src/di.ts",
"packages/core/src/di/index.ts",
"packages/core/src/di/injectable.ts",
"packages/core/src/di/jit/injectable.ts",
"packages/core/src/di/jit/environment.ts",
"packages/core/src/di/injector_compatibility.ts",
"packages/core/src/di/injector.ts",
"packages/core/src/di/r3_injector.ts",
"packages/core/src/render3/definition.ts",
"packages/core/src/metadata/ng_module.ts"
],
[
"packages/core/src/application_ref.ts",
"packages/core/src/application_tokens.ts",
@ -904,6 +883,12 @@
"packages/core/src/change_detection/differs/default_keyvalue_differ.ts",
"packages/core/src/change_detection/differs/keyvalue_differs.ts"
],
[
"packages/core/src/debug/debug_node.ts",
"packages/core/src/view/index.ts",
"packages/core/src/view/entrypoint.ts",
"packages/core/src/view/services.ts"
],
[
"packages/core/src/di/injectable.ts",
"packages/core/src/di/jit/injectable.ts"

View File

@ -12,7 +12,7 @@
"master": {
"uncompressed": {
"runtime-es2015": 3037,
"main-es2015": 448493,
"main-es2015": 447742,
"polyfills-es2015": 52415
}
}

View File

@ -21,7 +21,7 @@
"master": {
"uncompressed": {
"runtime-es2015": 1485,
"main-es2015": 146989,
"main-es2015": 146417,
"polyfills-es2015": 36571
}
}
@ -39,7 +39,7 @@
"master": {
"uncompressed": {
"runtime-es2015": 2289,
"main-es2015": 242351,
"main-es2015": 241850,
"polyfills-es2015": 36938,
"5-es2015": 751
}
@ -49,7 +49,7 @@
"master": {
"uncompressed": {
"runtime-es2015": 2289,
"main-es2015": 218961,
"main-es2015": 218329,
"polyfills-es2015": 36723,
"5-es2015": 781
}

View File

@ -7,6 +7,7 @@
*/
import {Injector} from '../di/injector';
import {assertTNodeForLView} from '../render3/assert';
import {CONTAINER_HEADER_OFFSET, LContainer, NATIVE} from '../render3/interfaces/container';
import {TElementNode, TNode, TNodeFlags, TNodeType} from '../render3/interfaces/node';
import {isComponentHost, isLContainer} from '../render3/interfaces/type_checks';
@ -15,7 +16,7 @@ import {getComponent, getContext, getInjectionTokens, getInjector, getListeners,
import {INTERPOLATION_DELIMITER, renderStringify} from '../render3/util/misc_utils';
import {getComponentLViewByIndex, getNativeByTNodeOrNull} from '../render3/util/view_utils';
import {assertDomNode} from '../util/assert';
import {DebugContext} from '../view/types';
import {DebugContext} from '../view/index';
@ -525,6 +526,7 @@ function _queryAllR3(
function _queryNodeChildrenR3(
tNode: TNode, lView: LView, predicate: Predicate<DebugElement>|Predicate<DebugNode>,
matches: DebugElement[]|DebugNode[], elementsOnly: boolean, rootNativeNode: any) {
ngDevMode && assertTNodeForLView(tNode, lView);
const nativeNode = getNativeByTNodeOrNull(tNode, lView);
// For each type of TNode, specific logic is executed.
if (tNode.type === TNodeType.Element || tNode.type === TNodeType.ElementContainer) {
@ -616,9 +618,11 @@ function _queryNodeChildrenInContainerR3(
lContainer: LContainer, predicate: Predicate<DebugElement>|Predicate<DebugNode>,
matches: DebugElement[]|DebugNode[], elementsOnly: boolean, rootNativeNode: any) {
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
const childView = lContainer[i];
_queryNodeChildrenR3(
childView[TVIEW].node!, childView, predicate, matches, elementsOnly, rootNativeNode);
const childView = lContainer[i] as LView;
const firstChild = childView[TVIEW].firstChild;
if (firstChild) {
_queryNodeChildrenR3(firstChild, childView, predicate, matches, elementsOnly, rootNativeNode);
}
}
}
@ -658,7 +662,7 @@ function _addQueryMatchR3(
*
* @param nativeNode the current native node
* @param predicate the predicate to match
* @param matches the list of positive matches
* @param matches the list where matches are stored
* @param elementsOnly whether only elements should be searched
*/
function _queryNativeNodeDescendants(

View File

@ -9,6 +9,7 @@
import '../util/ng_dev_mode';
import {Type} from '../interface/type';
import {assertNotEqual} from '../util/assert';
import {getClosureSafeProperty} from '../util/property';
import {stringify} from '../util/stringify';
@ -84,6 +85,19 @@ export function setInjectImplementation(
return previous;
}
/**
* Assert that `_injectImplementation` is not `fn`.
*
* This is useful, to prevent infinite recursion.
*
* @param fn Function which it should not equal to
*/
export function assertInjectImplementationNot(
fn: (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T | null)) {
ngDevMode &&
assertNotEqual(_injectImplementation, fn, 'Calling ɵɵinject would cause infinite recursion');
}
export function injectInjectorOnly<T>(token: Type<T>|InjectionToken<T>): T;
export function injectInjectorOnly<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags): T|
null;

View File

@ -6,14 +6,16 @@
* found in the LICENSE file at https://angular.io/license
*/
import {assertDefined, assertEqual, assertIndexInRange, assertNumber, throwError} from '../util/assert';
import {getComponentDef, getNgModuleDef} from './definition';
import {LContainer} from './interfaces/container';
import {DirectiveDef} from './interfaces/definition';
import { assertDefined, assertEqual, assertNumber, throwError } from '../util/assert';
import { getComponentDef, getNgModuleDef } from './definition';
import { LContainer } from './interfaces/container';
import { DirectiveDef } from './interfaces/definition';
import { PARENT_INJECTOR } from './interfaces/injector';
import {TNode} from './interfaces/node';
import {isLContainer, isLView} from './interfaces/type_checks';
import {HEADER_OFFSET, LView, TVIEW, TView} from './interfaces/view';
import { TNode } from './interfaces/node';
import { isLContainer, isLView } from './interfaces/type_checks';
import { HEADER_OFFSET, LView, TVIEW, TView } from './interfaces/view';
// [Assert functions do not constraint type when they are guarded by a truthy
// expression.](https://github.com/microsoft/TypeScript/issues/37295)
@ -147,4 +149,4 @@ export function assertNodeInjector(lView: LView, injectorIndex: number) {
assertNumber(
lView[injectorIndex + 8 /*PARENT_INJECTOR*/],
'injectorIndex should point to parent injector');
}
}

View File

@ -129,9 +129,9 @@ export function renderComponent<T>(
const rootContext = createRootContext(opts.scheduler, opts.playerHandler);
const renderer = rendererFactory.createRenderer(hostRNode, componentDef);
const rootTView = createTView(TViewType.Root, -1, null, 1, 0, null, null, null, null, null);
const rootTView = createTView(TViewType.Root, null, null, 1, 0, null, null, null, null, null);
const rootView: LView = createLView(
null, rootTView, rootContext, rootFlags, null, null, rendererFactory, renderer, undefined,
null, rootTView, rootContext, rootFlags, null, null, rendererFactory, renderer, null,
opts.injector || null);
enterView(rootView);
@ -193,7 +193,7 @@ export function createRootComponentView(
const componentView = createLView(
rootView, getOrCreateTComponentView(def), null,
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, rootView[HEADER_OFFSET], tNode,
rendererFactory, viewRenderer, sanitizer);
rendererFactory, viewRenderer, sanitizer || null, null);
if (tView.firstCreatePass) {
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), tView, def.type);

View File

@ -19,18 +19,16 @@ import {RendererFactory2} from '../render/api';
import {Sanitizer} from '../sanitization/sanitizer';
import {VERSION} from '../version';
import {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from '../view/provider';
import {assertComponentType} from './assert';
import {createRootComponent, createRootComponentView, createRootContext, LifecycleHooksFeature} from './component';
import {getComponentDef} from './definition';
import {NodeInjector} from './di';
import {assignTViewNodeToLView, createLView, createTView, elementCreate, locateHostElement, renderView} from './instructions/shared';
import {createLView, createTView, elementCreate, locateHostElement, renderView} from './instructions/shared';
import {ComponentDef} from './interfaces/definition';
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType} from './interfaces/node';
import {TContainerNode, TElementContainerNode, TElementNode, TNode} from './interfaces/node';
import {domRendererFactory3, RendererFactory3, RNode} from './interfaces/renderer';
import {LView, LViewFlags, TVIEW, TViewType} from './interfaces/view';
import {LView, LViewFlags, TViewType} from './interfaces/view';
import {MATH_ML_NAMESPACE, SVG_NAMESPACE} from './namespaces';
import {assertNodeOfPossibleTypes} from './node_assert';
import {writeDirectClass} from './node_manipulation';
import {extractAttrsAndClassesFromSelector, stringifyCSSSelectorList} from './node_selector_matcher';
import {enterView, leaveView} from './state';
@ -158,7 +156,7 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
const rootContext = createRootContext();
// Create the root view. Uses empty TView and ContentTemplate.
const rootTView = createTView(TViewType.Root, -1, null, 1, 0, null, null, null, null, null);
const rootTView = createTView(TViewType.Root, null, null, 1, 0, null, null, null, null, null);
const rootLView = createLView(
null, rootTView, rootContext, rootFlags, null, null, rendererFactory, hostRenderer,
sanitizer, rootViewInjector);
@ -223,11 +221,6 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
const componentRef = new ComponentRef(
this.componentType, component,
createElementRef(viewEngine_ElementRef, tElementNode, rootLView), rootLView, tElementNode);
// The host element of the internal root view is attached to the component's host view node.
ngDevMode && assertNodeOfPossibleTypes(rootTView.node, [TNodeType.View]);
rootTView.node!.child = tElementNode;
return componentRef;
}
}
@ -267,7 +260,6 @@ export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
super();
this.instance = instance;
this.hostView = this.changeDetectorRef = new RootViewRef<T>(_rootLView);
assignTViewNodeToLView(_rootLView[TVIEW], null, -1, _rootLView);
this.componentType = componentType;
}

View File

@ -190,13 +190,11 @@ export function isDirectiveInstance(instance: any): boolean {
* Locates the element within the given LView and returns the matching index
*/
function findViaNativeElement(lView: LView, target: RElement): number {
let tNode = lView[TVIEW].firstChild;
while (tNode) {
const native = getNativeByTNodeOrNull(tNode, lView)!;
if (native === target) {
return tNode.index;
const tView = lView[TVIEW];
for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
if (unwrapRNode(lView[i]) === target) {
return i;
}
tNode = traverseNextElement(tNode);
}
return -1;
@ -206,7 +204,11 @@ function findViaNativeElement(lView: LView, target: RElement): number {
* Locates the next tNode (child, sibling or parent).
*/
function traverseNextElement(tNode: TNode): TNode|null {
if (tNode.child) {
if (tNode.child && tNode.child.parent === tNode) {
// FIXME(misko): checking if `tNode.child.parent === tNode` should not be necessary
// We have added it here because i18n creates TNode's which are not valid, so this is a work
// around. The i18n code is being refactored in #??? and once it lands this extra check can be
// deleted.
return tNode.child;
} else if (tNode.next) {
return tNode.next;

View File

@ -13,10 +13,10 @@ import {injectRootLimpMode, setInjectImplementation} from '../di/injector_compat
import {getInjectorDef} from '../di/interface/defs';
import {InjectFlags} from '../di/interface/injector';
import {Type} from '../interface/type';
import {assertDefined, assertEqual} from '../util/assert';
import {assertDefined, assertEqual, assertIndexInRange, throwError} from '../util/assert';
import {noSideEffects} from '../util/closure';
import {assertDirectiveDef} from './assert';
import {assertDirectiveDef, assertNodeInjector, assertTNodeForLView} from './assert';
import {getFactoryDef} from './definition';
import {NG_ELEMENT_ID, NG_FACTORY_DEF} from './fields';
import {registerPreOrderHooks} from './hooks';
@ -24,7 +24,7 @@ import {DirectiveDef, FactoryFn} from './interfaces/definition';
import {isFactory, NO_PARENT_INJECTOR, NodeInjectorFactory, PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags, TNODE} from './interfaces/injector';
import {AttributeMarker, TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TNode, TNodeProviderIndexes, TNodeType} from './interfaces/node';
import {isComponentDef, isComponentHost} from './interfaces/type_checks';
import {DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, INJECTOR, LView, T_HOST, TData, TVIEW, TView} from './interfaces/view';
import {DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, INJECTOR, LView, T_HOST, TData, TVIEW, TView, TViewType} from './interfaces/view';
import {assertNodeOfPossibleTypes} from './node_assert';
import {enterDI, leaveDI} from './state';
import {isNameOnlyAttributeMarker} from './util/attrs_utils';
@ -184,16 +184,17 @@ function insertBloom(arr: any[], footer: TNode|null): void {
}
export function getInjectorIndex(tNode: TNode, hostView: LView): number {
export function getInjectorIndex(tNode: TNode, lView: LView): number {
if (tNode.injectorIndex === -1 ||
// If the injector index is the same as its parent's injector index, then the index has been
// copied down from the parent node. No injector has been created yet on this node.
(tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) ||
// After the first template pass, the injector index might exist but the parent values
// might not have been calculated yet for this instance
hostView[tNode.injectorIndex + PARENT_INJECTOR] == null) {
lView[tNode.injectorIndex + PARENT_INJECTOR] == null) {
return -1;
} else {
ngDevMode && assertIndexInRange(lView, tNode.injectorIndex);
return tNode.injectorIndex;
}
}
@ -204,25 +205,55 @@ export function getInjectorIndex(tNode: TNode, hostView: LView): number {
*
* Returns a combination of number of `LView` we have to go up and index in that `LView`
*/
export function getParentInjectorLocation(tNode: TNode, view: LView): RelativeInjectorLocation {
export function getParentInjectorLocation(tNode: TNode, lView: LView): RelativeInjectorLocation {
if (tNode.parent && tNode.parent.injectorIndex !== -1) {
// If we have a parent `TNode` and there is an injector associated with it we are done, because
// the parent injector is within the current `LView`.
return tNode.parent.injectorIndex as any; // ViewOffset is 0
}
// For most cases, the parent injector index can be found on the host node (e.g. for component
// or container), so this loop will be skipped, but we must keep the loop here to support
// the rarer case of deeply nested <ng-template> tags or inline views.
let hostTNode = view[T_HOST];
let viewOffset = 1;
while (hostTNode && hostTNode.injectorIndex === -1) {
view = view[DECLARATION_VIEW]!;
hostTNode = view ? view[T_HOST] : null;
viewOffset++;
}
// When parent injector location is computed it may be outside of the current view. (ie it could
// be pointing to a declared parent location). This variable stores number of declaration parents
// we need to walk up in order to find the parent injector location.
let declarationViewOffset = 0;
let parentTNode: TNode|null = null;
let lViewCursor: LView|null = lView;
return hostTNode ?
hostTNode.injectorIndex | (viewOffset << RelativeInjectorLocationFlags.ViewOffsetShift) :
-1 as any;
// The parent injector is not in the current `LView`. We will have to walk the declared parent
// `LView` hierarchy and look for it. If we walk of the top, that means that there is no parent
// `NodeInjector`.
while (lViewCursor !== null) {
// First determine the `parentTNode` location. The parent pointer differs based on `TView.type`.
const tView = lViewCursor[TVIEW];
const tViewType = tView.type;
if (tViewType === TViewType.Embedded) {
ngDevMode && assertDefined(tView.node, 'Embedded TNodes should have declaration parents.');
parentTNode = tView.node;
} else if (tViewType === TViewType.Component) {
// Components don't have `TView.declTNode` because each instance of component could be
// inserted in different location, hence `TView.declTNode` is meaningless.
parentTNode = lViewCursor[T_HOST];
} else {
ngDevMode && assertEqual(tView.type, TViewType.Root, 'Root type expected');
parentTNode = null;
}
if (parentTNode === null) {
// If we have no parent, than we are done.
return NO_PARENT_INJECTOR;
}
ngDevMode && parentTNode && assertTNodeForLView(parentTNode!, lViewCursor[DECLARATION_VIEW]!);
// Every iteration of the loop requires that we go to the declared parent.
declarationViewOffset++;
lViewCursor = lViewCursor[DECLARATION_VIEW];
if (parentTNode.injectorIndex !== -1) {
// We found a NodeInjector which points to something.
return (parentTNode.injectorIndex |
(declarationViewOffset << RelativeInjectorLocationFlags.ViewOffsetShift)) as any;
}
}
return NO_PARENT_INJECTOR;
}
/**
@ -367,13 +398,12 @@ export function getOrCreateInjectable<T>(
flags & InjectFlags.Host ? lView[DECLARATION_COMPONENT_VIEW][T_HOST] : null;
// If we should skip this injector, or if there is no injector on this node, start by
// searching
// the parent injector.
// searching the parent injector.
if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) {
parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) :
lView[injectorIndex + PARENT_INJECTOR];
if (!shouldSearchParent(flags, false)) {
if (parentLocation === NO_PARENT_INJECTOR || !shouldSearchParent(flags, false)) {
injectorIndex = -1;
} else {
previousTView = lView[TVIEW];
@ -385,10 +415,11 @@ export function getOrCreateInjectable<T>(
// Traverse up the injector tree until we find a potential match or until we know there
// *isn't* a match.
while (injectorIndex !== -1) {
parentLocation = lView[injectorIndex + PARENT_INJECTOR];
ngDevMode && assertNodeInjector(lView, injectorIndex);
// Check the current injector. If it matches, see if it contains token.
const tView = lView[TVIEW];
ngDevMode && assertTNodeForLView(tView.data[injectorIndex + TNODE] as TNode, lView);
if (bloomHasToken(bloomHash, injectorIndex, tView.data)) {
// At this point, we have an injector which *may* contain the token, so we step through
// the providers and directives associated with the injector's corresponding node to get
@ -399,7 +430,9 @@ export function getOrCreateInjectable<T>(
return instance;
}
}
if (shouldSearchParent(
parentLocation = lView[injectorIndex + PARENT_INJECTOR];
if (parentLocation !== NO_PARENT_INJECTOR &&
shouldSearchParent(
flags, lView[TVIEW].data[injectorIndex + TNODE] === hostTElementNode) &&
bloomHasToken(bloomHash, injectorIndex, lView)) {
// The def wasn't found anywhere on this node, so it was a false positive.
@ -453,7 +486,7 @@ function searchTokensOnInjector<T>(
const currentTView = lView[TVIEW];
const tNode = currentTView.data[injectorIndex + TNODE] as TNode;
// First, we need to determine if view providers can be accessed by the starting element.
// There are two possibities
// There are two possibilities
const canAccessViewProviders = previousTView == null ?
// 1) This is the first invocation `previousTView == null` which means that we are at the
// `TNode` of where injector is starting to look. In such a case the only time we are allowed
@ -544,10 +577,8 @@ export function getNodeInjectable(
}
const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders);
factory.resolving = true;
let previousInjectImplementation;
if (factory.injectImpl) {
previousInjectImplementation = setInjectImplementation(factory.injectImpl);
}
const previousInjectImplementation =
factory.injectImpl ? setInjectImplementation(factory.injectImpl) : null;
enterDI(lView, tNode);
try {
value = lView[index] = factory.factory(undefined, tData, lView, tNode);
@ -562,7 +593,8 @@ export function getNodeInjectable(
registerPreOrderHooks(index, tData[index] as DirectiveDef<any>, tView);
}
} finally {
if (factory.injectImpl) setInjectImplementation(previousInjectImplementation);
previousInjectImplementation !== null &&
setInjectImplementation(previousInjectImplementation);
setIncludeViewProviders(previousIncludeViewProviders);
factory.resolving = false;
leaveDI();

View File

@ -354,7 +354,13 @@ function appendI18nNode(
// Re-organize node tree to put this node in the correct position.
if (previousTNode === parentTNode && tNode !== parentTNode.child) {
tNode.next = parentTNode.child;
parentTNode.child = tNode;
// FIXME(misko): Checking `tNode.parent` is a temporary workaround until we properly
// refactor the i18n code in #38707 and this code will be deleted.
if (tNode.parent === null) {
tView.firstChild = tNode;
} else {
parentTNode.child = tNode;
}
} else if (previousTNode !== parentTNode && tNode !== previousTNode.next) {
tNode.next = previousTNode.next;
previousTNode.next = tNode;
@ -446,7 +452,7 @@ function removeNode(tView: TView, lView: LView, index: number, markAsDetached: b
}
}
if (markAsDetached) {
if (markAsDetached && removedPhTNode) {
// Define this node as detached to avoid projecting it later
removedPhTNode.flags |= TNodeFlags.isDetached;
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {InjectFlags, InjectionToken, resolveForwardRef} from '../../di';
import {ɵɵinject} from '../../di/injector_compatibility';
import {assertInjectImplementationNot, ɵɵinject} from '../../di/injector_compatibility';
import {Type} from '../../interface/type';
import {getOrCreateInjectable, injectAttributeImpl} from '../di';
import {TDirectiveHostNode} from '../interfaces/node';
@ -43,7 +43,11 @@ export function ɵɵdirectiveInject<T>(
const lView = getLView();
// Fall back to inject() if view hasn't been created. This situation can happen in tests
// if inject utilities are used before bootstrapping.
if (lView == null) return ɵɵinject(token, flags);
if (lView === null) {
// Verify that we will not get into infinite loop.
ngDevMode && assertInjectImplementationNot(ɵɵdirectiveInject);
return ɵɵinject(token, flags);
}
const tNode = getPreviousOrParentTNode();
return getOrCreateInjectable<T>(
tNode as TDirectiveHostNode, lView, resolveForwardRef(token), flags);

View File

@ -17,7 +17,7 @@ import {getInjectorIndex} from '../di';
import {CONTAINER_HEADER_OFFSET, HAS_TRANSPLANTED_VIEWS, LContainer, MOVED_VIEWS, NATIVE} from '../interfaces/container';
import {ComponentTemplate, DirectiveDef, DirectiveDefList, PipeDefList, ViewQueriesFunction} from '../interfaces/definition';
import {NO_PARENT_INJECTOR, PARENT_INJECTOR, TNODE} from '../interfaces/injector';
import {AttributeMarker, PropertyAliases, TConstants, TContainerNode, TElementNode, TNode as ITNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TNodeTypeAsString, TViewNode} from '../interfaces/node';
import {AttributeMarker, PropertyAliases, TConstants, TContainerNode, TElementNode, TNode as ITNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TNodeTypeAsString} from '../interfaces/node';
import {SelectorFlags} from '../interfaces/projection';
import {LQueries, TQueries} from '../interfaces/query';
import {RComment, RElement, Renderer3, RendererFactory3, RNode} from '../interfaces/renderer';
@ -116,12 +116,11 @@ function nameSuffix(text: string|null|undefined): string {
export const TViewConstructor = class TView implements ITView {
constructor(
public type: TViewType, //
public id: number, //
public blueprint: LView, //
public template: ComponentTemplate<{}>|null, //
public queries: TQueries|null, //
public viewQuery: ViewQueriesFunction<{}>|null, //
public node: TViewNode|TElementNode|null, //
public node: ITNode|null, //
public data: TData, //
public bindingStartIndex: number, //
public expandoStartIndex: number, //
@ -493,7 +492,7 @@ export class LViewDebug implements ILViewDebug {
get queries(): LQueries|null {
return this._raw_lView[QUERIES];
}
get tHost(): TViewNode|TElementNode|null {
get tHost(): ITNode|null {
return this._raw_lView[T_HOST];
}

View File

@ -17,7 +17,7 @@ import {createNamedArrayType} from '../../util/named_array_type';
import {initNgDevMode} from '../../util/ng_dev_mode';
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../../util/ng_reflect';
import {stringify} from '../../util/stringify';
import {assertFirstCreatePass, assertLContainer, assertLView} from '../assert';
import {assertFirstCreatePass, assertLContainer, assertLView, assertTNodeForLView} from '../assert';
import {attachPatchData} from '../context_discovery';
import {getFactoryDef} from '../definition';
import {diPublicInInjector, getNodeInjectable, getOrCreateNodeInjectorForNode} from '../di';
@ -172,13 +172,14 @@ export function elementCreate(name: string, renderer: Renderer3, namespace: stri
export function createLView<T>(
parentLView: LView|null, tView: TView, context: T|null, flags: LViewFlags, host: RElement|null,
tHostNode: TViewNode|TElementNode|null, rendererFactory?: RendererFactory3|null,
renderer?: Renderer3|null, sanitizer?: Sanitizer|null, injector?: Injector|null): LView {
tHostNode: TNode|null, rendererFactory: RendererFactory3|null, renderer: Renderer3|null,
sanitizer: Sanitizer|null, injector: Injector|null): LView {
const lView =
ngDevMode ? cloneToLViewFromTViewBlueprint(tView) : tView.blueprint.slice() as LView;
lView[HOST] = host;
lView[FLAGS] = flags | LViewFlags.CreationMode | LViewFlags.Attached | LViewFlags.FirstLViewPass;
resetPreOrderHookFlags(lView);
ngDevMode && tView.node && parentLView && assertTNodeForLView(tView.node, parentLView);
lView[PARENT] = lView[DECLARATION_VIEW] = parentLView;
lView[CONTEXT] = context;
lView[RENDERER_FACTORY] = (rendererFactory || parentLView && parentLView[RENDERER_FACTORY])!;
@ -250,7 +251,7 @@ function createTNodeAtIndex(
const parentInSameView = parent !== null && parent.type !== TNodeType.View;
const tParentNode = parentInSameView ? parent as TElementNode | TContainerNode : null;
const tNode = tView.data[adjustedIndex] =
createTNode(tView, tParentNode, type, adjustedIndex, name, attrs);
createTNode(tView, parent as TElementNode | TContainerNode, type, adjustedIndex, name, attrs);
// Assign a pointer to the first child node of a given view. The first node is not always the one
// at index 0, in case of i18n, index 0 can be the instruction `i18nStart` and the first node has
// the index 1 or more, so we can't just check node index.
@ -269,23 +270,6 @@ function createTNodeAtIndex(
return tNode;
}
export function assignTViewNodeToLView(
tView: TView, tParentNode: TNode|null, index: number, lView: LView): void {
// View nodes are not stored in data because they can be added / removed at runtime (which
// would cause indices to change). Their TNodes are instead stored in tView.node.
let tNode = tView.node;
if (tNode == null) {
ngDevMode && tParentNode &&
assertNodeOfPossibleTypes(tParentNode, [TNodeType.Element, TNodeType.Container]);
tView.node = tNode = createTNode(
tView,
tParentNode as TElementNode | TContainerNode | null, //
TNodeType.View, index, null, null) as TViewNode;
}
lView[T_HOST] = tNode as TViewNode;
}
/**
* When elements are created dynamically after a view blueprint is created (e.g. through
@ -623,8 +607,11 @@ export function getOrCreateTComponentView(def: ComponentDef<any>): TView {
// Create a TView if there isn't one, or recreate it if the first create pass didn't
// complete successfully since we can't know for sure whether it's in a usable shape.
if (tView === null || tView.incompleteFirstPass) {
// Declaration node here is null since this function is called when we dynamically create a
// component and hence there is no declaration.
const declTNode = null;
return def.tView = createTView(
TViewType.Component, -1, def.template, def.decls, def.vars, def.directiveDefs,
TViewType.Component, declTNode, def.template, def.decls, def.vars, def.directiveDefs,
def.pipeDefs, def.viewQuery, def.schemas, def.consts);
}
@ -635,7 +622,8 @@ export function getOrCreateTComponentView(def: ComponentDef<any>): TView {
/**
* Creates a TView instance
*
* @param viewIndex The viewBlockId for inline views, or -1 if it's a component/dynamic
* @param type Type of `TView`.
* @param declTNode Declaration location of this `TView`.
* @param templateFn Template function
* @param decls The number of nodes, local refs, and pipes in this template
* @param directives Registry of directives for this view
@ -645,7 +633,7 @@ export function getOrCreateTComponentView(def: ComponentDef<any>): TView {
* @param consts Constants for this view
*/
export function createTView(
type: TViewType, viewIndex: number, templateFn: ComponentTemplate<any>|null, decls: number,
type: TViewType, declTNode: TNode|null, templateFn: ComponentTemplate<any>|null, decls: number,
vars: number, directives: DirectiveDefListOrFactory|null, pipes: PipeDefListOrFactory|null,
viewQuery: ViewQueriesFunction<any>|null, schemas: SchemaMetadata[]|null,
constsOrFactory: TConstantsOrFactory|null): TView {
@ -660,12 +648,11 @@ export function createTView(
const tView = blueprint[TVIEW as any] = ngDevMode ?
new TViewConstructor(
type,
viewIndex, // id: number,
blueprint, // blueprint: LView,
templateFn, // template: ComponentTemplate<{}>|null,
null, // queries: TQueries|null
viewQuery, // viewQuery: ViewQueriesFunction<{}>|null,
null!, // node: TViewNode|TElementNode|null,
declTNode, // declTNode: TNode|null,
cloneToTViewData(blueprint).fill(null, bindingStartIndex), // data: TData,
bindingStartIndex, // bindingStartIndex: number,
initialViewLength, // expandoStartIndex: number,
@ -697,12 +684,11 @@ export function createTView(
) :
{
type: type,
id: viewIndex,
blueprint: blueprint,
template: templateFn,
queries: null,
viewQuery: viewQuery,
node: null!,
node: declTNode,
data: blueprint.slice().fill(null, bindingStartIndex),
bindingStartIndex: bindingStartIndex,
expandoStartIndex: initialViewLength,
@ -812,6 +798,7 @@ export function storeCleanupWithContext(
* Constructs a TNode object from the arguments.
*
* @param tView `TView` to which this `TNode` belongs (used only in `ngDevMode`)
* @param tParent Parent `TNode`
* @param type The type of the node
* @param adjustedIndex The index of the TNode in TView.data, adjusted for HEADER_OFFSET
* @param tagName The tag name of the node
@ -1488,7 +1475,8 @@ function addComponentLogic<T>(lView: LView, hostTNode: TElementNode, def: Compon
lView,
createLView(
lView, tView, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, native,
hostTNode as TElementNode, rendererFactory, rendererFactory.createRenderer(native, def)));
hostTNode as TElementNode, rendererFactory, rendererFactory.createRenderer(native, def),
null, null));
// Component view will always be created before any injected LContainers,
// so this is a regular element, wrap it with the component view

View File

@ -35,13 +35,8 @@ function templateFirstCreatePass(
registerPostOrderHooks(tView, tNode);
const embeddedTView = tNode.tViews = createTView(
TViewType.Embedded, -1, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry,
null, tView.schemas, tViewConsts);
const embeddedTViewNode =
createTNode(embeddedTView, null, TNodeType.View, -1, null, null) as TViewNode;
embeddedTViewNode.injectorIndex = tNode.injectorIndex;
// FIXME(misko): remove `embeddedTView.node'
embeddedTView.node = embeddedTView.firstChild = embeddedTViewNode;
TViewType.Embedded, tNode, templateFn, decls, vars, tView.directiveRegistry,
tView.pipeRegistry, null, tView.schemas, tViewConsts);
if (tView.queries !== null) {
tView.queries.template(tView, tNode);

View File

@ -14,6 +14,11 @@ import {assertDefined, assertEqual} from '../../util/assert';
import {TDirectiveHostNode} from './node';
import {LView, TData} from './view';
/**
* Offset from 'injectorIndex' where:
* - `TViewData[injectorIndex + TNODE]` => `TNode` associated with the current injector.
* - `LView[injectorIndex + TNODE]` => index to the parent injector.
*/
export const TNODE = 8;
export const PARENT_INJECTOR = 8;
export const INJECTOR_BLOOM_PARENT_SIZE = 9;

View File

@ -41,6 +41,7 @@ export const RENDERER = 11;
export const SANITIZER = 12;
export const CHILD_HEAD = 13;
export const CHILD_TAIL = 14;
// FIXME(misko): Investigate if the three declarations aren't all same thing.
export const DECLARATION_VIEW = 15;
export const DECLARATION_COMPONENT_VIEW = 16;
export const DECLARATION_LCONTAINER = 17;
@ -79,8 +80,7 @@ export interface LView extends Array<any> {
debug?: LViewDebug;
/**
* The host node for this LView instance, if this is a component view.
* If this is an embedded view, HOST will be null.
* The node into which this `LView` is inserted.
*/
[HOST]: RElement|null;
@ -120,16 +120,35 @@ export interface LView extends Array<any> {
[QUERIES]: LQueries|null;
/**
* Pointer to the `TViewNode` or `TElementNode` which represents the root of the view.
* Store the `TNode` of the location where the current `LView` is inserted into.
*
* If `TViewNode`, this is an embedded view of a container. We need this to be able to
* efficiently find the `LViewNode` when inserting the view into an anchor.
* Given:
* ```
* <div>
* <ng-template><span></span></ng-template>
* </div>
* ```
*
* If `TElementNode`, this is the LView of a component.
* We end up with two `TView`s.
* - `parent` `TView` which contains `<div><!-- anchor --></div>`
* - `child` `TView` which contains `<span></span>`
*
* If null, this is the root view of an application (root component is in this view).
* Typically the `child` is inserted into the declaration location of the `parent`, but it can be
* inserted anywhere. Because it can be inserted anywhere it is not possible to store the
* insertion information in the `TView` and instead we must store it in the `LView[T_HOST]`.
*
* So to determine where is our insertion parent we would execute:
* ```
* const parentLView = lView[PARENT];
* const parentTNode = lView[T_HOST];
* const insertionParent = parentLView[parentTNode.index];
* ```
*
*
* If `null`, this is the root view of an application (root component is in this view) and it has
* no parents.
*/
[T_HOST]: TViewNode|TElementNode|null;
[T_HOST]: TNode|null;
/**
* When a view is destroyed, listeners need to be released and outputs need to be
@ -183,8 +202,6 @@ export interface LView extends Array<any> {
/**
* View where this view's template was declared.
*
* Only applicable for dynamically created views. Will be null for inline/component views.
*
* The template for a dynamically created view may be declared in a different view than
* it is inserted. We already track the "insertion view" (view where the template was
* inserted) in LView[PARENT], but we also need access to the "declaration view"
@ -439,6 +456,17 @@ export const enum TViewType {
Embedded = 2,
}
/**
* Converts `TViewType` into human readable text.
* Make sure this matches with `TViewType`
*/
export const TViewTypeAsString = [
'Root', // 0
'Component', // 1
'Embedded', // 2
] as const;
/**
* The static data for an LView (shared between all templates of a
* given type).
@ -451,15 +479,6 @@ export interface TView {
*/
type: TViewType;
/**
* ID for inline views to determine whether a view is the same as the previous view
* in a certain position. If it's not, we know the new view needs to be inserted
* and the one that exists needs to be removed (e.g. if/else statements)
*
* If this is -1, then this is a component view or a dynamically created view.
*/
readonly id: number;
/**
* This is a blueprint used to generate LView instances for this TView. Copying this
* blueprint is faster than creating a new LView from scratch.
@ -478,21 +497,12 @@ export interface TView {
viewQuery: ViewQueriesFunction<{}>|null;
/**
* Pointer to the host `TNode` (not part of this TView).
*
* If this is a `TViewNode` 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 `TElementNode`, this is the view of a root component. It has exactly one
* root TNode.
*
* If this is null, this is the view of a component that is not at root. We do not store
* the host TNodes for child component views because they can potentially have several
* different host TNodes, depending on where the component is being used. These host
* TNodes cannot be shared (due to different indices, etc).
* A `TNode` representing the declaration location of this `TView` (not part of this TView).
*/
node: TViewNode|TElementNode|null;
// FIXME(misko): Rename `node` to `declTNode`
node: TNode|null;
// FIXME(misko): Why does `TView` not have `declarationTView` property?
/** Whether or not this template has been processed in creation mode. */
firstCreatePass: boolean;
@ -1038,7 +1048,7 @@ export interface DebugNode {
injector: NodeInjectorDebug;
}
interface NodeInjectorDebug {
export interface NodeInjectorDebug {
/**
* Instance bloom. Does the current injector have a provider with a given bloom mask.
*/

View File

@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Renderer2} from '../core';
import {ViewEncapsulation} from '../metadata/view';
import {Renderer2} from '../render/api';
import {addToArray, removeFromArray} from '../util/array_utils';
import {assertDefined, assertDomNode, assertEqual, assertSame, assertString} from '../util/assert';
@ -20,7 +20,7 @@ import {TElementNode, TNode, TNodeFlags, TNodeType, TProjectionNode, TViewNode,
import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection';
import {isProceduralRenderer, ProceduralRenderer3, RElement, Renderer3, RNode, RText, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer';
import {isLContainer, isLView} from './interfaces/type_checks';
import {CHILD_HEAD, CLEANUP, DECLARATION_COMPONENT_VIEW, DECLARATION_LCONTAINER, DestroyHookData, FLAGS, HookData, HookFn, HOST, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, T_HOST, TVIEW, TView, unusedValueExportToPlacateAjd as unused5} from './interfaces/view';
import {CHILD_HEAD, CLEANUP, DECLARATION_COMPONENT_VIEW, DECLARATION_LCONTAINER, DestroyHookData, FLAGS, HookData, HookFn, HOST, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, T_HOST, TVIEW, TView, TViewType, unusedValueExportToPlacateAjd as unused5} from './interfaces/view';
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
import {getLViewParent} from './util/view_traversal_utils';
import {getNativeByTNode, getNonViewFirstChild, unwrapRNode, updateTransplantedViewCount} from './util/view_utils';
@ -125,7 +125,7 @@ export function createTextNode(value: string, renderer: Renderer3): RText {
}
/**
* Adds or removes all DOM elements associated with a view.
* Removes all DOM elements associated with a view.
*
* Because some root nodes of the view may be containers, we sometimes need
* to propagate deeply into the nested containers to remove all elements in the
@ -133,24 +133,37 @@ export function createTextNode(value: string, renderer: Renderer3): RText {
*
* @param tView The `TView' of the `LView` from which elements should be added or removed
* @param lView The view from which elements should be added or removed
* @param insertMode Whether or not elements should be added (if false, removing)
*/
export function removeViewFromContainer(tView: TView, lView: LView): void {
const renderer = lView[RENDERER];
applyView(tView, lView, renderer, WalkTNodeTreeAction.Detach, null, null);
lView[HOST] = null;
lView[T_HOST] = null;
}
/**
* Adds all DOM elements associated with a view.
*
* Because some root nodes of the view may be containers, we sometimes need
* to propagate deeply into the nested containers to add all elements in the
* views beneath it.
*
* @param tView The `TView' of the `LView` from which elements should be added or removed
* @param parentTNode The `TNode` where the `LView` should be attached to.
* @param renderer Current renderer to use for DOM manipulations.
* @param lView The view from which elements should be added or removed
* @param parentNativeNode The parent `RElement` where it should be inserted into.
* @param beforeNode The node before which elements should be added, if insert mode
*/
export function addRemoveViewFromContainer(
tView: TView, lView: LView, insertMode: true, beforeNode: RNode|null): void;
export function addRemoveViewFromContainer(
tView: TView, lView: LView, insertMode: false, beforeNode: null): void;
export function addRemoveViewFromContainer(
tView: TView, lView: LView, insertMode: boolean, beforeNode: RNode|null): void {
const renderParent = getContainerRenderParent(tView.node as TViewNode, lView);
ngDevMode && assertNodeType(tView.node as TNode, TNodeType.View);
if (renderParent) {
const renderer = lView[RENDERER];
const action = insertMode ? WalkTNodeTreeAction.Insert : WalkTNodeTreeAction.Detach;
applyView(tView, lView, renderer, action, renderParent, beforeNode);
}
export function addViewToContainer(
tView: TView, parentTNode: TNode, renderer: Renderer3, lView: LView, parentNativeNode: RElement,
beforeNode: RNode|null): void {
lView[HOST] = parentNativeNode;
lView[T_HOST] = parentTNode;
applyView(tView, lView, renderer, WalkTNodeTreeAction.Insert, parentNativeNode, beforeNode);
}
/**
* Detach a `LView` from the DOM by detaching its nodes.
*
@ -334,7 +347,7 @@ export function detachView(lContainer: LContainer, removeIndex: number): LView|u
lContainer[indexInContainer - 1][NEXT] = viewToDetach[NEXT] as LView;
}
const removedLView = removeFromArray(lContainer, CONTAINER_HEADER_OFFSET + removeIndex);
addRemoveViewFromContainer(viewToDetach[TVIEW], viewToDetach, false, null);
removeViewFromContainer(viewToDetach[TVIEW], viewToDetach);
// notify query that a view has been removed
const lQueries = removedLView[QUERIES];
@ -417,10 +430,8 @@ function cleanUpView(tView: TView, lView: LView): void {
executeOnDestroys(tView, lView);
removeListeners(tView, lView);
const hostTNode = lView[T_HOST];
// For component views only, the local renderer is destroyed as clean up time.
if (hostTNode && hostTNode.type === TNodeType.Element &&
isProceduralRenderer(lView[RENDERER])) {
// For component views only, the local renderer is destroyed at clean up time.
if (lView[TVIEW].type === TViewType.Component && isProceduralRenderer(lView[RENDERER])) {
ngDevMode && ngDevMode.rendererDestroy++;
(lView[RENDERER] as ProceduralRenderer3).destroy();
}
@ -530,7 +541,7 @@ function getRenderParent(tView: TView, tNode: TNode, currentView: LView): REleme
// or a component view.
if (parentTNode == null) {
const hostTNode = currentView[T_HOST]!;
if (hostTNode.type === TNodeType.View) {
if (hostTNode && hostTNode.type === TNodeType.View) {
// We are inserting a root element of an embedded view We might delay insertion of children
// for a given view if it is disconnected. This might happen for 2 main reasons:
// - view is not inserted into any container(view was created but not inserted yet)
@ -542,7 +553,6 @@ function getRenderParent(tView: TView, tNode: TNode, currentView: LView): REleme
} else {
// We are inserting a root element of the component view into the component host element and
// it should always be eager.
ngDevMode && assertNodeOfPossibleTypes(hostTNode, [TNodeType.Element]);
return currentView[HOST];
}
} else {
@ -817,15 +827,19 @@ function applyNodes(
* @param lView The LView which needs to be inserted, detached, destroyed.
* @param renderer Renderer to use
* @param action action to perform (insert, detach, destroy)
* @param renderParent parent DOM element for insertion/removal.
* @param renderParent parent DOM element for insertion (Removal does not need it).
* @param beforeNode Before which node the insertions should happen.
*/
function applyView(
tView: TView, lView: LView, renderer: Renderer3, action: WalkTNodeTreeAction.Destroy,
renderParent: null, beforeNode: null): void;
function applyView(
tView: TView, lView: LView, renderer: Renderer3, action: WalkTNodeTreeAction,
renderParent: RElement|null, beforeNode: RNode|null) {
ngDevMode && assertNodeType(tView.node!, TNodeType.View);
const viewRootTNode: TNode|null = getNonViewFirstChild(tView);
applyNodes(renderer, action, viewRootTNode, lView, renderParent, beforeNode, false);
renderParent: RElement|null, beforeNode: RNode|null): void;
function applyView(
tView: TView, lView: LView, renderer: Renderer3, action: WalkTNodeTreeAction,
renderParent: RElement|null, beforeNode: RNode|null): void {
applyNodes(renderer, action, tView.firstChild, lView, renderParent, beforeNode, false);
}
/**

View File

@ -1,51 +0,0 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {RelativeInjectorLocation} from './interfaces/injector';
import {TContainerNode, TElementNode, TNode} from './interfaces/node';
import {DECLARATION_VIEW, LView, T_HOST} from './interfaces/view';
import {getParentInjectorViewOffset} from './util/injector_utils';
/**
* If `startTNode.parent` exists and has an injector, returns TNode for that injector.
* Otherwise, unwraps a parent injector location number to find the view offset from the current
* injector, then walks up the declaration view tree until the TNode of the parent injector is
* found.
*
* @param location The location of the parent injector, which contains the view offset
* @param startView The LView instance from which to start walking up the view tree
* @param startTNode The TNode instance of the starting element
* @returns The TNode of the parent injector
*/
export function getParentInjectorTNode(
location: RelativeInjectorLocation, startView: LView, startTNode: TNode): TElementNode|
TContainerNode|null {
// If there is an injector on the parent TNode, retrieve the TNode for that injector.
if (startTNode.parent && startTNode.parent.injectorIndex !== -1) {
// view offset is 0
const injectorIndex = startTNode.parent.injectorIndex;
let tNode = startTNode.parent;
// If tNode.injectorIndex === tNode.parent.injectorIndex, then the index belongs to a parent
// injector.
while (tNode.parent != null && injectorIndex == tNode.parent.injectorIndex) {
tNode = tNode.parent;
}
return tNode;
}
let viewOffset = getParentInjectorViewOffset(location);
// view offset is 1
let parentView = startView;
let parentTNode = startView[T_HOST] as TElementNode;
// view offset is superior to 1
while (viewOffset > 1) {
parentView = parentView[DECLARATION_VIEW]!;
parentTNode = parentView[T_HOST] as TElementNode;
viewOffset--;
}
return parentTNode;
}

View File

@ -48,13 +48,17 @@ export function ɵɵpipe(index: number, pipeName: string): any {
const pipeFactory = pipeDef.factory || (pipeDef.factory = getFactoryDef(pipeDef.type, true));
const previousInjectImplementation = setInjectImplementation(ɵɵdirectiveInject);
let pipeInstance: any;
// DI for pipes is supposed to behave like directives when placed on a component
// host node, which means that we have to disable access to `viewProviders`.
const previousIncludeViewProviders = setIncludeViewProviders(false);
const pipeInstance = pipeFactory();
setIncludeViewProviders(previousIncludeViewProviders);
setInjectImplementation(previousInjectImplementation);
try {
// DI for pipes is supposed to behave like directives when placed on a component
// host node, which means that we have to disable access to `viewProviders`.
const previousIncludeViewProviders = setIncludeViewProviders(false);
pipeInstance = pipeFactory();
setIncludeViewProviders(previousIncludeViewProviders);
} finally {
setInjectImplementation(previousInjectImplementation);
}
store(tView, getLView(), index, pipeInstance);
return pipeInstance;
}

View File

@ -7,6 +7,7 @@
*/
import {Injector} from '../../di/injector';
import {assertEqual} from '../../util/assert';
import {assertLView} from '../assert';
import {discoverLocalRefs, getComponentAtNodeIndex, getDirectivesAtNodeIndex, getLContext} from '../context_discovery';
import {NodeInjector} from '../di';
@ -15,7 +16,7 @@ import {LContext} from '../interfaces/context';
import {DirectiveDef} from '../interfaces/definition';
import {TElementNode, TNode, TNodeProviderIndexes} from '../interfaces/node';
import {isLView} from '../interfaces/type_checks';
import {CLEANUP, CONTEXT, DebugNode, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, T_HOST, TVIEW} from '../interfaces/view';
import {CLEANUP, CONTEXT, DebugNode, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, T_HOST, TVIEW, TViewType} from '../interfaces/view';
import {stringifyForError} from './misc_utils';
import {getLViewParent, getRootContext} from './view_traversal_utils';
@ -101,8 +102,7 @@ export function getOwningComponent<T>(elementOrDir: Element|{}): T|null {
let lView = context.lView;
let parent: LView|null;
ngDevMode && assertLView(lView);
while (lView[HOST] === null && (parent = getLViewParent(lView)!)) {
// As long as lView[HOST] is null we know we are part of sub-template such as `*ngIf`
while (lView[TVIEW].type === TViewType.Embedded && (parent = getLViewParent(lView)!)) {
lView = parent;
}
return lView[FLAGS] & LViewFlags.IsRoot ? null : lView[CONTEXT] as T;
@ -389,6 +389,8 @@ export function getDebugNode(element: Element): DebugNode|null {
// data. In this situation the TNode is not accessed at the same spot.
const tNode = isLView(valueInLView) ? (valueInLView[T_HOST] as TNode) :
getTNode(lView[TVIEW], nodeIndex - HEADER_OFFSET);
ngDevMode &&
assertEqual(tNode.index, nodeIndex, 'Expecting that TNode at index is same as index');
debugNode = buildDebugNode(tNode, lView);
}

View File

@ -5,14 +5,26 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {assertGreaterThan, assertNotEqual, assertNumber} from '../../util/assert';
import {NO_PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags} from '../interfaces/injector';
import {DECLARATION_VIEW, LView} from '../interfaces/view';
import {DECLARATION_VIEW, HEADER_OFFSET, LView} from '../interfaces/view';
/// Parent Injector Utils ///////////////////////////////////////////////////////////////
export function hasParentInjector(parentLocation: RelativeInjectorLocation): boolean {
return parentLocation !== NO_PARENT_INJECTOR;
}
export function getParentInjectorIndex(parentLocation: RelativeInjectorLocation): number {
ngDevMode && assertNumber(parentLocation, 'Number expected');
ngDevMode && assertNotEqual(parentLocation as any, -1, 'Not a valid state.');
const parentInjectorIndex =
(parentLocation as any as number) & RelativeInjectorLocationFlags.InjectorIndexMask;
ngDevMode &&
assertGreaterThan(
parentInjectorIndex, HEADER_OFFSET,
'Parent injector must be pointing past HEADER_OFFSET.');
return (parentLocation as any as number) & RelativeInjectorLocationFlags.InjectorIndexMask;
}

View File

@ -105,10 +105,10 @@ export function getNativeByTNode(tNode: TNode, lView: LView): RNode {
* @param tNode
* @param lView
*/
export function getNativeByTNodeOrNull(tNode: TNode, lView: LView): RNode|null {
const index = tNode.index;
export function getNativeByTNodeOrNull(tNode: TNode|null, lView: LView): RNode|null {
const index = tNode === null ? -1 : tNode.index;
if (index !== -1) {
ngDevMode && assertTNodeForLView(tNode, lView);
ngDevMode && assertTNodeForLView(tNode!, lView);
const node: RNode|null = unwrapRNode(lView[index]);
ngDevMode && node !== null && !isProceduralRenderer(lView[RENDERER]) && assertDomNode(node);
return node;
@ -216,6 +216,7 @@ export function updateTransplantedViewCount(lContainer: LContainer, amount: 1|-
* crashes on it, so we unwrap it.
*/
export function getNonViewFirstChild(tView: TView): TNode|null {
// FIXME(misko): Delete me! (as TNodeType.View no longer exists)
const firstChild = tView.firstChild;
return firstChild === null ? null :
(firstChild.type === TNodeType.View ? firstChild.child : firstChild);

View File

@ -6,33 +6,33 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectorRef as ViewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref';
import {Injector} from '../di/injector';
import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref';
import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory';
import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
import {ViewContainerRef as ViewEngine_ViewContainerRef} from '../linker/view_container_ref';
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref';
import {Renderer2} from '../render/api';
import {addToArray, removeFromArray} from '../util/array_utils';
import {assertDefined, assertEqual, assertGreaterThan, assertLessThan} from '../util/assert';
import { ChangeDetectorRef as ViewEngine_ChangeDetectorRef } from '../change_detection/change_detector_ref';
import { Injector } from '../di/injector';
import { ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef } from '../linker/component_factory';
import { ElementRef as ViewEngine_ElementRef } from '../linker/element_ref';
import { NgModuleRef as viewEngine_NgModuleRef } from '../linker/ng_module_factory';
import { TemplateRef as ViewEngine_TemplateRef } from '../linker/template_ref';
import { ViewContainerRef as ViewEngine_ViewContainerRef } from '../linker/view_container_ref';
import { EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef } from '../linker/view_ref';
import { Renderer2 } from '../render/api';
import { addToArray, removeFromArray } from '../util/array_utils';
import { assertDefined, assertEqual, assertGreaterThan, assertLessThan } from '../util/assert';
import { assertLContainer, assertNodeInjector } from './assert';
import { getParentInjectorLocation, NodeInjector } from './di';
import { addToViewTree, createLContainer, createLView, renderView } from './instructions/shared';
import { CONTAINER_HEADER_OFFSET, LContainer, NATIVE, VIEW_REFS } from './interfaces/container';
import { TNODE } from './interfaces/injector';
import { TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TNode, TNodeType } from './interfaces/node';
import { isProceduralRenderer, RComment, RElement } from './interfaces/renderer';
import { isComponentHost, isLContainer, isLView, isRootView } from './interfaces/type_checks';
import { DECLARATION_COMPONENT_VIEW, DECLARATION_LCONTAINER, LView, LViewFlags, PARENT, QUERIES, RENDERER, TVIEW, TView, T_HOST } from './interfaces/view';
import { assertNodeOfPossibleTypes } from './node_assert';
import { addViewToContainer, appendChild, destroyLView, detachView, getBeforeNodeForView, insertView, nativeInsertBefore, nativeNextSibling, nativeParentNode } from './node_manipulation';
import { getLView, getPreviousOrParentTNode } from './state';
import { getParentInjectorIndex, getParentInjectorView, hasParentInjector } from './util/injector_utils';
import { getComponentLViewByIndex, getNativeByTNode, unwrapRNode, viewAttachedToContainer } from './util/view_utils';
import { ViewRef } from './view_ref';
import {assertLContainer} from './assert';
import {getParentInjectorLocation, NodeInjector} from './di';
import {addToViewTree, createLContainer, createLView, renderView} from './instructions/shared';
import {CONTAINER_HEADER_OFFSET, LContainer, VIEW_REFS} from './interfaces/container';
import {TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TNode, TNodeType} from './interfaces/node';
import {isProceduralRenderer, RComment, RElement} from './interfaces/renderer';
import {isComponentHost, isLContainer, isLView, isRootView} from './interfaces/type_checks';
import {DECLARATION_COMPONENT_VIEW, DECLARATION_LCONTAINER, LView, LViewFlags, PARENT, QUERIES, RENDERER, T_HOST, TVIEW, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes} from './node_assert';
import {addRemoveViewFromContainer, appendChild, destroyLView, detachView, getBeforeNodeForView, insertView, nativeInsertBefore, nativeNextSibling, nativeParentNode} from './node_manipulation';
import {getParentInjectorTNode} from './node_util';
import {getLView, getPreviousOrParentTNode} from './state';
import {getParentInjectorView, hasParentInjector} from './util/injector_utils';
import {getComponentLViewByIndex, getNativeByTNode, unwrapRNode, viewAttachedToContainer} from './util/view_utils';
import {ViewRef} from './view_ref';
@ -106,7 +106,7 @@ export function createTemplateRef<T>(
const embeddedTView = this._declarationTContainer.tViews as TView;
const embeddedLView = createLView(
this._declarationView, embeddedTView, context, LViewFlags.CheckAlways, null,
embeddedTView.node);
embeddedTView.node, null, null, null, null);
const declarationLContainer = this._declarationView[this._declarationTContainer.index];
ngDevMode && assertLContainer(declarationLContainer);
@ -188,12 +188,15 @@ export function createContainerRef(
/** @deprecated No replacement */
get parentInjector(): Injector {
const parentLocation = getParentInjectorLocation(this._hostTNode, this._hostView);
const parentView = getParentInjectorView(parentLocation, this._hostView);
const parentTNode = getParentInjectorTNode(parentLocation, this._hostView, this._hostTNode);
return !hasParentInjector(parentLocation) || parentTNode == null ?
new NodeInjector(null, this._hostView) :
new NodeInjector(parentTNode, parentView);
if (hasParentInjector(parentLocation)) {
const parentView = getParentInjectorView(parentLocation, this._hostView);
const injectorIndex = getParentInjectorIndex(parentLocation);
ngDevMode && assertNodeInjector(parentView, injectorIndex);
const parentTNode = parentView[TVIEW].data[injectorIndex + TNODE] as TElementNode;
return new NodeInjector(parentTNode, parentView);
} else {
return new NodeInjector(null, this._hostView);
}
}
clear(): void {
@ -277,14 +280,21 @@ export function createContainerRef(
}
}
// Logical operation of adding `LView` to `LContainer`
const adjustedIdx = this._adjustIndex(index);
insertView(tView, lView, this._lContainer, adjustedIdx);
const lContainer = this._lContainer;
insertView(tView, lView, lContainer, adjustedIdx);
const beforeNode = getBeforeNodeForView(adjustedIdx, this._lContainer);
addRemoveViewFromContainer(tView, lView, true, beforeNode);
// Physical operation of adding the DOM nodes.
const beforeNode = getBeforeNodeForView(adjustedIdx, lContainer);
const renderer = lView[RENDERER];
const renderParent = nativeParentNode(renderer, lContainer[NATIVE] as RElement | RComment);
if (renderParent !== null) {
addViewToContainer(tView, lContainer[T_HOST], renderer, lView, renderParent, beforeNode);
}
(viewRef as ViewRef<any>).attachToViewContainerRef(this);
addToArray(this._lContainer[VIEW_REFS]!, adjustedIdx, viewRef);
addToArray(lContainer[VIEW_REFS]!, adjustedIdx, viewRef);
return viewRef;
}

View File

@ -35,11 +35,8 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int
get rootNodes(): any[] {
const lView = this._lView;
if (lView[HOST] == null) {
const hostTView = lView[T_HOST] as TViewNode;
return collectNativeNodes(lView[TVIEW], lView, hostTView.child, []);
}
return [];
const tView = lView[TVIEW];
return collectNativeNodes(tView, lView, tView.firstChild, []);
}
constructor(

View File

@ -7,7 +7,7 @@
*/
import {CommonModule} from '@angular/common';
import {Attribute, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, forwardRef, Host, HostBinding, Inject, Injectable, InjectionToken, INJECTOR, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, NgZone, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, ViewRef, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID} from '@angular/core';
import {Attribute, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, forwardRef, Host, HostBinding, Inject, Injectable, InjectionToken, INJECTOR, Injector, Input, LOCALE_ID, NgModule, NgZone, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, ViewRef, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID} from '@angular/core';
import {ɵINJECTOR_SCOPE} from '@angular/core/src/core';
import {ViewRef as ViewRefInternal} from '@angular/core/src/render3/view_ref';
import {TestBed} from '@angular/core/testing';

View File

@ -53,7 +53,7 @@ describe('acceptance integration tests', () => {
expect(fixture.nativeElement.innerHTML).toEqual('<h1>Hello, World!</h1>');
onlyInIvy('perf counters').expectPerfCounters({
tView: 2, // Host view + App
tNode: 4, // Host Node + App Node + <span> + #text
tNode: 3, // Host Node + <h1> + #text
});
fixture.componentInstance.name = 'New World';
@ -63,7 +63,7 @@ describe('acceptance integration tests', () => {
// Assert that the tView/tNode count does not increase (they are correctly cached)
onlyInIvy('perf counters').expectPerfCounters({
tView: 2,
tNode: 4,
tNode: 3,
});
});
});

View File

@ -797,7 +797,7 @@ describe('styling', () => {
onlyInIvy('perf counters').expectPerfCounters({
rendererSetStyle: 1,
tNode: 3,
tNode: 2,
});
});

View File

@ -704,9 +704,6 @@
{
"name": "addHostBindingsToExpandoInstructions"
},
{
"name": "addRemoveViewFromContainer"
},
{
"name": "addToArray"
},
@ -821,9 +818,6 @@
{
"name": "createPlatformFactory"
},
{
"name": "createTNode"
},
{
"name": "createTView"
},
@ -974,9 +968,6 @@
{
"name": "getConstant"
},
{
"name": "getContainerRenderParent"
},
{
"name": "getDOM"
},
@ -1064,9 +1055,6 @@
{
"name": "getParentInjectorView"
},
{
"name": "getParentInjectorViewOffset"
},
{
"name": "getParentState"
},

View File

@ -59,9 +59,6 @@
{
"name": "allocLFrame"
},
{
"name": "appendChild"
},
{
"name": "attachPatchData"
},
@ -110,6 +107,9 @@
{
"name": "extractPipeDef"
},
{
"name": "getBeforeNodeForView"
},
{
"name": "getCheckNoChangesMode"
},
@ -235,5 +235,8 @@
},
{
"name": "viewAttachedToChangeDetector"
},
{
"name": "ɵɵtext"
}
]

View File

@ -926,9 +926,6 @@
{
"name": "addHostBindingsToExpandoInstructions"
},
{
"name": "addRemoveViewFromContainer"
},
{
"name": "addToArray"
},
@ -1070,9 +1067,6 @@
{
"name": "createRouterScroller"
},
{
"name": "createTNode"
},
{
"name": "createTView"
},
@ -1286,9 +1280,6 @@
{
"name": "getConstant"
},
{
"name": "getContainerRenderParent"
},
{
"name": "getCurrentQueryIndex"
},
@ -1394,9 +1385,6 @@
{
"name": "getParentInjectorView"
},
{
"name": "getParentInjectorViewOffset"
},
{
"name": "getParentState"
},

View File

@ -179,9 +179,6 @@
{
"name": "addHostBindingsToExpandoInstructions"
},
{
"name": "addRemoveViewFromContainer"
},
{
"name": "addToArray"
},
@ -260,9 +257,6 @@
{
"name": "createLView"
},
{
"name": "createTNode"
},
{
"name": "createTView"
},
@ -353,9 +347,6 @@
{
"name": "getConstant"
},
{
"name": "getContainerRenderParent"
},
{
"name": "getDebugContext"
},
@ -425,9 +416,6 @@
{
"name": "getParentInjectorView"
},
{
"name": "getParentInjectorViewOffset"
},
{
"name": "getParentState"
},

View File

@ -226,8 +226,8 @@ describe('di', () => {
describe('getOrCreateNodeInjector', () => {
it('should handle initial undefined state', () => {
const contentView = createLView(
null, createTView(TViewType.Component, -1, null, 1, 0, null, null, null, null, null), {},
LViewFlags.CheckAlways, null, null, {} as any, {} as any);
null, createTView(TViewType.Component, null, null, 1, 0, null, null, null, null, null),
{}, LViewFlags.CheckAlways, null, null, {} as any, {} as any, null, null);
enterView(contentView);
try {
const parentTNode = getOrCreateTNode(contentView[TVIEW], 0, TNodeType.Element, null, null);

View File

@ -26,7 +26,7 @@ describe('lView_debug', () => {
let tNode!: TNodeDebug;
let tView!: TView;
beforeEach(() => {
tView = createTView(TViewType.Component, 0, null, 0, 0, null, null, null, null, null);
tView = createTView(TViewType.Component, null, null, 0, 0, null, null, null, null, null);
tNode = createTNode(tView, null!, TNodeType.Element, 0, '', null) as TNodeDebug;
});
afterEach(() => tNode = tView = null!);

View File

@ -36,7 +36,7 @@ export function enterViewWithOneDiv() {
const vars = 60; // Space for directive expando, template, component + 3 directives if we assume
// that each consume 10 slots.
const tView = createTView(
TViewType.Component, -1, emptyTemplate, consts, vars, null, null, null, null, null);
TViewType.Component, null, emptyTemplate, consts, vars, null, null, null, null, null);
// Just assume that the expando starts after 10 initial bindings.
tView.expandoStartIndex = HEADER_OFFSET + 10;
const tNode = tView.firstChild = createTNode(tView, null!, TNodeType.Element, 0, 'div', null);

View File

@ -91,7 +91,6 @@ export function isTView(obj: any): obj is TView {
}
const ShapeOfTView: ShapeOf<TView> = {
type: true,
id: true,
blueprint: true,
template: true,
viewQuery: true,

View File

@ -52,7 +52,7 @@ describe('render3 matchers', () => {
});
describe('matchTView', () => {
const tView = createTView(TViewType.Root, 1, null, 2, 3, null, null, null, null, null);
const tView = createTView(TViewType.Root, null, null, 2, 3, null, null, null, null, null);
it('should match', () => {
expect(tView).toEqual(matchTView());
expect(tView).toEqual(matchTView({type: TViewType.Root}));
@ -60,7 +60,7 @@ describe('render3 matchers', () => {
});
});
describe('matchTNode', () => {
const tView = createTView(TViewType.Root, 1, null, 2, 3, null, null, null, null, null);
const tView = createTView(TViewType.Root, null, null, 2, 3, null, null, null, null, null);
const tNode = createTNode(tView, null, TNodeType.Element, 1, 'tagName', []);
it('should match', () => {

View File

@ -75,12 +75,12 @@ function testTemplate(rf: RenderFlags, ctx: any) {
}
const rootLView = createLView(
null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null);
null, createTView(TViewType.Root, null, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null, null, null, null, null);
const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode;
const embeddedTView = createTView(
TViewType.Embedded, -1, testTemplate, 21, 10, [Tooltip.ɵdir], null, null, null,
TViewType.Embedded, null, testTemplate, 21, 10, [Tooltip.ɵdir], null, null, null,
[['position', 'top', 3, 'tooltip']]);
// create view once so we don't profile the first create pass

View File

@ -64,12 +64,12 @@ function testTemplate(rf: RenderFlags, ctx: any) {
}
const rootLView = createLView(
null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null);
null, createTView(TViewType.Root, null, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null, null, null, null, null);
const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode;
const embeddedTView = createTView(
TViewType.Embedded, -1, testTemplate, 21, 0, null, null, null, null, [[
TViewType.Embedded, null, testTemplate, 21, 0, null, null, null, null, [[
'name1', 'value1', 'name2', 'value2', 'name3', 'value3', 'name4', 'value4', 'name5', 'value5'
]]);

View File

@ -66,12 +66,12 @@ function testTemplate(rf: RenderFlags, ctx: any) {
}
const rootLView = createLView(
null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null);
null, createTView(TViewType.Root, null, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null, null, null, null, null);
const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode;
const embeddedTView = createTView(
TViewType.Embedded, -1, testTemplate, 11, 0, null, null, null, null, [[3, 'click', 'input']]);
TViewType.Embedded, null, testTemplate, 11, 0, null, null, null, null, [[3, 'click', 'input']]);
// create view once so we don't profile the first create pass
createAndRenderLView(rootLView, embeddedTView, viewTNode);

View File

@ -59,12 +59,12 @@ function testTemplate(rf: RenderFlags, ctx: any) {
}
const rootLView = createLView(
null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null);
null, createTView(TViewType.Root, null, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null, null, null, null, null);
const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode;
const embeddedTView = createTView(
TViewType.Root, -1, testTemplate, 2, 0, [NgIfLike.ɵdir], null, null, null,
TViewType.Root, null, testTemplate, 2, 0, [NgIfLike.ɵdir], null, null, null,
[['viewManipulation', '']]);
// create view once so we don't profile first template pass

View File

@ -22,7 +22,8 @@ const renderer = rendererFactory.createRenderer(null, null);
export function createAndRenderLView(
parentLView: LView, tView: TView, hostTNode: TViewNode): LView {
const embeddedLView = createLView(
parentLView, tView, {}, LViewFlags.CheckAlways, null, hostTNode, rendererFactory, renderer);
parentLView, tView, {}, LViewFlags.CheckAlways, null, hostTNode, rendererFactory, renderer,
null, null);
renderView(tView, embeddedLView, null);
return embeddedLView;
}
@ -49,12 +50,12 @@ export function setupTestHarness(
embeddedViewContext: any = {}, consts: TAttributes[]|null = null,
directiveRegistry: DirectiveDefList|null = null): TestHarness {
// Create a root view with a container
const hostTView = createTView(TViewType.Root, -1, null, 1, 0, null, null, null, null, consts);
const hostTView = createTView(TViewType.Root, null, null, 1, 0, null, null, null, null, consts);
const tContainerNode = getOrCreateTNode(hostTView, 0, TNodeType.Container, null, null);
const hostNode = renderer.createElement('div');
const hostLView = createLView(
null, hostTView, {}, LViewFlags.CheckAlways | LViewFlags.IsRoot, hostNode, null,
rendererFactory, renderer);
rendererFactory, renderer, null, null);
const mockRCommentNode = renderer.createComment('');
const lContainer =
createLContainer(mockRCommentNode, hostLView, mockRCommentNode, tContainerNode);
@ -63,13 +64,14 @@ export function setupTestHarness(
// create test embedded views
const embeddedTView = createTView(
TViewType.Embedded, -1, templateFn, decls, vars, directiveRegistry, null, null, null, consts);
TViewType.Embedded, null, templateFn, decls, vars, directiveRegistry, null, null, null,
consts);
const viewTNode = createTNode(hostTView, null, TNodeType.View, -1, null, null) as TViewNode;
function createEmbeddedLView(): LView {
const embeddedLView = createLView(
hostLView, embeddedTView, embeddedViewContext, LViewFlags.CheckAlways, null, viewTNode,
rendererFactory, renderer);
rendererFactory, renderer, null, null);
renderView(embeddedTView, embeddedLView, embeddedViewContext);
return embeddedLView;
}

View File

@ -52,12 +52,12 @@ function testTemplate(rf: RenderFlags, ctx: any) {
}
const rootLView = createLView(
null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null);
null, createTView(TViewType.Root, null, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null, null, null, null, null);
const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode;
const embeddedTView = createTView(
TViewType.Embedded, -1, testTemplate, 21, 10, [ToDestroy.ɵdir], null, null, null,
TViewType.Embedded, null, testTemplate, 21, 10, [ToDestroy.ɵdir], null, null, null,
[['to-destroy']]);
// create view once so we don't profile the first create pass

View File

@ -261,10 +261,10 @@ export function renderTemplate<T>(
const renderer = providedRendererFactory.createRenderer(null, null);
// We need to create a root view so it's possible to look up the host element through its index
const tView = createTView(TViewType.Root, -1, null, 1, 0, null, null, null, null, null);
const tView = createTView(TViewType.Root, null, null, 1, 0, null, null, null, null, null);
const hostLView = createLView(
null, tView, {}, LViewFlags.CheckAlways | LViewFlags.IsRoot, null, null,
providedRendererFactory, renderer);
providedRendererFactory, renderer, null, null);
enterView(hostLView);
const def: ComponentDef<any> = ɵɵdefineComponent({
@ -282,7 +282,7 @@ export function renderTemplate<T>(
hostLView[hostTNode.index] = hostNode;
componentView = createLView(
hostLView, componentTView, context, LViewFlags.CheckAlways, hostNode, hostTNode,
providedRendererFactory, renderer, sanitizer);
providedRendererFactory, renderer, sanitizer || null, null);
}
renderComponentOrTemplate(componentView[TVIEW], componentView, templateFn, context);
return componentView;

View File

@ -13,7 +13,7 @@ import {TViewType} from '@angular/core/src/render3/interfaces/view';
describe('view_utils', () => {
it('should verify unwrap methods', () => {
const div = document.createElement('div');
const tView = createTView(TViewType.Root, 0, null, 0, 0, null, null, null, null, null);
const tView = createTView(TViewType.Root, null, null, 0, 0, null, null, null, null, null);
const lView = createLView(null, tView, {}, 0, div, null, {} as any, {} as any, null, null);
const tNode = createTNode(null!, null, 3, 0, 'div', []);
const lContainer = createLContainer(lView, lView, div, tNode);