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:
		
							parent
							
								
									b2579d43cd
								
							
						
					
					
						commit
						eb32b6bd6b
					
				| @ -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" | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
|     "master": { | ||||
|       "uncompressed": { | ||||
|         "runtime-es2015": 3037, | ||||
|         "main-es2015": 448493, | ||||
|         "main-es2015": 447742, | ||||
|         "polyfills-es2015": 52415 | ||||
|       } | ||||
|     } | ||||
|  | ||||
| @ -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 | ||||
|       } | ||||
|  | ||||
| @ -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( | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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'); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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; | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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(); | ||||
|  | ||||
| @ -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; | ||||
|   } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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]; | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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. | ||||
|    */ | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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; | ||||
|       } | ||||
|  | ||||
| @ -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( | ||||
|  | ||||
| @ -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'; | ||||
|  | ||||
| @ -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, | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
| @ -797,7 +797,7 @@ describe('styling', () => { | ||||
| 
 | ||||
|     onlyInIvy('perf counters').expectPerfCounters({ | ||||
|       rendererSetStyle: 1, | ||||
|       tNode: 3, | ||||
|       tNode: 2, | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|  | ||||
| @ -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" | ||||
|   }, | ||||
|  | ||||
| @ -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" | ||||
|   } | ||||
| ] | ||||
| @ -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" | ||||
|   }, | ||||
|  | ||||
| @ -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" | ||||
|   }, | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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!); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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', () => { | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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' | ||||
|     ]]); | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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; | ||||
|   } | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user