feat: introduce TestBed.overrideProvider (#16725)

This allows to overwrite all providers for a token, not matter
where they were defined.

This can be used to test JIT and AOT’ed code in the same way.

Design doc: https://docs.google.com/document/d/1VmTkz0EbEVSWfEEWEvQ5sXyQXSCvtMOw4t7pKU-jOwc/edit?usp=sharing
This commit is contained in:
Tobias Bosch
2017-05-15 13:12:10 -07:00
committed by Jason Aden
parent 1eba623d12
commit 39b92f7e54
20 changed files with 735 additions and 121 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {APP_INITIALIZER, ApplicationInitStatus} from './application_init';
import {ApplicationInitStatus} from './application_init';
import {ApplicationRef, ApplicationRef_} from './application_ref';
import {APP_ID_RANDOM_PROVIDER} from './application_tokens';
import {IterableDiffers, KeyValueDiffers, defaultIterableDiffers, defaultKeyValueDiffers} from './change_detection/change_detection';
@ -14,7 +14,6 @@ import {Inject, Optional, SkipSelf} from './di/metadata';
import {LOCALE_ID} from './i18n/tokens';
import {Compiler} from './linker/compiler';
import {NgModule} from './metadata';
import {initServicesIfNeeded} from './view/index';
export function _iterableDiffersFactory() {
return defaultIterableDiffers;
@ -28,10 +27,6 @@ export function _localeFactory(locale?: string): string {
return locale || 'en-US';
}
export function _initViewEngine() {
initServicesIfNeeded();
}
/**
* This module includes the providers of @angular/core that are needed
* to bootstrap components via `ApplicationRef`.
@ -52,7 +47,6 @@ export function _initViewEngine() {
useFactory: _localeFactory,
deps: [[new Inject(LOCALE_ID), new Optional(), new SkipSelf()]]
},
{provide: APP_INITIALIZER, useValue: _initViewEngine, multi: true},
]
})
export class ApplicationModule {

View File

@ -26,4 +26,5 @@ export {DirectRenderer as ɵDirectRenderer, RenderDebugInfo as ɵRenderDebugInfo
export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util';
export {makeDecorator as ɵmakeDecorator} from './util/decorators';
export {isObservable as ɵisObservable, isPromise as ɵisPromise} from './util/lang';
export {clearProviderOverrides as ɵclearProviderOverrides, overrideProvider as ɵoverrideProvider} from './view/index';
export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider';

View File

@ -0,0 +1,50 @@
/**
* @license
* Copyright Google Inc. 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 {Injector} from '../di/injector';
import {NgModuleFactory, NgModuleRef} from '../linker/ng_module_factory';
import {Type} from '../type';
import {initServicesIfNeeded} from './services';
import {NgModuleDefinitionFactory, ProviderOverride, Services} from './types';
import {resolveDefinition} from './util';
export function overrideProvider(override: ProviderOverride) {
initServicesIfNeeded();
return Services.overrideProvider(override);
}
export function clearProviderOverrides() {
initServicesIfNeeded();
return Services.clearProviderOverrides();
}
// Attention: this function is called as top level function.
// Putting any logic in here will destroy closure tree shaking!
export function createNgModuleFactory(
ngModuleType: Type<any>, bootstrapComponents: Type<any>[],
defFactory: NgModuleDefinitionFactory): NgModuleFactory<any> {
return new NgModuleFactory_(ngModuleType, bootstrapComponents, defFactory);
}
class NgModuleFactory_ extends NgModuleFactory<any> {
constructor(
public readonly moduleType: Type<any>, private _bootstrapComponents: Type<any>[],
private _ngModuleDefFactory: NgModuleDefinitionFactory) {
// Attention: this ctor is called as top level function.
// Putting any logic in here will destroy closure tree shaking!
super();
}
create(parentInjector: Injector|null): NgModuleRef<any> {
initServicesIfNeeded();
const def = resolveDefinition(this._ngModuleDefFactory);
return Services.createNgModuleRef(
this.moduleType, parentInjector || Injector.NULL, this._bootstrapComponents, def);
}
}

View File

@ -7,13 +7,13 @@
*/
export {anchorDef, elementDef} from './element';
export {clearProviderOverrides, createNgModuleFactory, overrideProvider} from './entrypoint';
export {ngContentDef} from './ng_content';
export {moduleDef, moduleProvideDef} from './ng_module';
export {directiveDef, pipeDef, providerDef} from './provider';
export {pureArrayDef, pureObjectDef, purePipeDef} from './pure_expression';
export {queryDef} from './query';
export {ViewRef_, createComponentFactory, getComponentViewDefinitionFactory, nodeValue} from './refs';
export {createNgModuleFactory} from './refs';
export {initServicesIfNeeded} from './services';
export {textDef} from './text';
export {EMPTY_ARRAY, EMPTY_MAP, createRendererType2, elementEventFullName, inlineInterpolate, interpolate, rootRenderNodes, tokenKey, unwrapValue} from './util';

View File

@ -10,7 +10,7 @@ import {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
import {NgModuleRef} from '../linker/ng_module_factory';
import {DepDef, DepFlags, NgModuleData, NgModuleDefinition, NgModuleDefinitionFactory, NgModuleProviderDef, NodeFlags} from './types';
import {tokenKey} from './util';
import {splitDepsDsl, tokenKey} from './util';
const NOT_CREATED = new Object();
@ -20,17 +20,7 @@ const NgModuleRefTokenKey = tokenKey(NgModuleRef);
export function moduleProvideDef(
flags: NodeFlags, token: any, value: any,
deps: ([DepFlags, any] | any)[]): NgModuleProviderDef {
const depDefs: DepDef[] = deps.map(value => {
let token: any;
let flags: DepFlags;
if (Array.isArray(value)) {
[flags, token] = value;
} else {
flags = DepFlags.None;
token = value;
}
return {flags, token, tokenKey: tokenKey(token)};
});
const depDefs = splitDepsDsl(deps);
return {
// will bet set by the module definition
index: -1,
@ -97,16 +87,16 @@ function _createProviderInstance(ngModule: NgModuleData, providerDef: NgModulePr
let injectable: any;
switch (providerDef.flags & NodeFlags.Types) {
case NodeFlags.TypeClassProvider:
injectable = _createClass(ngModule, providerDef !.value, providerDef !.deps);
injectable = _createClass(ngModule, providerDef.value, providerDef.deps);
break;
case NodeFlags.TypeFactoryProvider:
injectable = _callFactory(ngModule, providerDef !.value, providerDef !.deps);
injectable = _callFactory(ngModule, providerDef.value, providerDef.deps);
break;
case NodeFlags.TypeUseExistingProvider:
injectable = resolveNgModuleDep(ngModule, providerDef !.deps[0]);
injectable = resolveNgModuleDep(ngModule, providerDef.deps[0]);
break;
case NodeFlags.TypeValueProvider:
injectable = providerDef !.value;
injectable = providerDef.value;
break;
}
return injectable;

View File

@ -15,7 +15,7 @@ import {Renderer as RendererV1, Renderer2} from '../render/api';
import {createChangeDetectorRef, createInjector, createRendererV1} from './refs';
import {BindingDef, BindingFlags, DepDef, DepFlags, NodeDef, NodeFlags, OutputDef, OutputType, ProviderData, QueryValueType, Services, ViewData, ViewFlags, ViewState, asElementData, asProviderData} from './types';
import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitDepsDsl, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
const RendererV1TokenKey = tokenKey(RendererV1);
const Renderer2TokenKey = tokenKey(Renderer2);
@ -78,17 +78,7 @@ export function _def(
bindings = [];
}
const depDefs: DepDef[] = deps.map(value => {
let token: any;
let flags: DepFlags;
if (Array.isArray(value)) {
[flags, token] = value;
} else {
flags = DepFlags.None;
token = value;
}
return {flags, token, tokenKey: tokenKey(token)};
});
const depDefs = splitDepsDsl(deps);
return {
// will bet set by the view definition

View File

@ -12,7 +12,7 @@ import {Injector} from '../di/injector';
import {ComponentFactory, ComponentRef} from '../linker/component_factory';
import {ComponentFactoryBoundToModule, ComponentFactoryResolver} from '../linker/component_factory_resolver';
import {ElementRef} from '../linker/element_ref';
import {InternalNgModuleRef, NgModuleFactory, NgModuleRef} from '../linker/ng_module_factory';
import {InternalNgModuleRef, NgModuleRef} from '../linker/ng_module_factory';
import {TemplateRef} from '../linker/template_ref';
import {ViewContainerRef} from '../linker/view_container_ref';
import {EmbeddedViewRef, InternalViewRef, ViewRef} from '../linker/view_ref';
@ -22,7 +22,7 @@ import {stringify} from '../util';
import {VERSION} from '../version';
import {callNgModuleLifecycle, initNgModule, resolveNgModuleDep} from './ng_module';
import {DepFlags, ElementData, NgModuleData, NgModuleDefinition, NgModuleDefinitionFactory, NodeDef, NodeFlags, Services, TemplateData, ViewContainerData, ViewData, ViewDefinitionFactory, ViewState, asElementData, asProviderData, asTextData} from './types';
import {DepFlags, ElementData, NgModuleData, NgModuleDefinition, NodeDef, NodeFlags, Services, TemplateData, ViewContainerData, ViewData, ViewDefinitionFactory, ViewState, asElementData, asProviderData, asTextData} from './types';
import {markParentViewsForCheck, resolveDefinition, rootRenderNodes, splitNamespace, tokenKey, viewParentEl} from './util';
import {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView, renderDetachView} from './view_attach';
@ -43,14 +43,6 @@ export function getComponentViewDefinitionFactory(componentFactory: ComponentFac
return (componentFactory as ComponentFactory_).viewDefFactory;
}
// Attention: this function is called as top level function.
// Putting any logic in here will destroy closure tree shaking!
export function createNgModuleFactory(
ngModuleType: Type<any>, bootstrapComponents: Type<any>[],
defFactory: NgModuleDefinitionFactory): NgModuleFactory<any> {
return new NgModuleFactory_(ngModuleType, bootstrapComponents, defFactory);
}
class ComponentFactory_ extends ComponentFactory<any> {
/**
* @internal
@ -312,7 +304,8 @@ class TemplateRef_ extends TemplateRef<any> implements TemplateData {
constructor(private _parentView: ViewData, private _def: NodeDef) { super(); }
createEmbeddedView(context: any): EmbeddedViewRef<any> {
return new ViewRef_(Services.createEmbeddedView(this._parentView, this._def, context));
return new ViewRef_(Services.createEmbeddedView(
this._parentView, this._def, this._def.element !.template !, context));
}
get elementRef(): ElementRef {
@ -464,22 +457,10 @@ class RendererAdapter implements RendererV1 {
}
class NgModuleFactory_ extends NgModuleFactory<any> {
constructor(
private _moduleType: Type<any>, private _bootstrapComponents: Type<any>[],
private _ngModuleDefFactory: NgModuleDefinitionFactory, ) {
// Attention: this ctor is called as top level function.
// Putting any logic in here will destroy closure tree shaking!
super();
}
get moduleType(): Type<any> { return this._moduleType; }
create(parentInjector: Injector|null): NgModuleRef<any> {
const def = resolveDefinition(this._ngModuleDefFactory);
return new NgModuleRef_(
this._moduleType, parentInjector || Injector.NULL, this._bootstrapComponents, def);
}
export function createNgModuleRef(
moduleType: Type<any>, parent: Injector, bootstrapComponents: Type<any>[],
def: NgModuleDefinition): NgModuleRef<any> {
return new NgModuleRef_(moduleType, parent, bootstrapComponents, def);
}
class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
@ -488,8 +469,8 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
public _providers: any[];
constructor(
private _moduleType: any, public _parent: Injector, public _bootstrapComponents: Type<any>[],
public _def: NgModuleDefinition) {
private _moduleType: Type<any>, public _parent: Injector,
public _bootstrapComponents: Type<any>[], public _def: NgModuleDefinition) {
initNgModule(this);
}

View File

@ -13,14 +13,15 @@ import {ErrorHandler} from '../error_handler';
import {NgModuleRef} from '../linker/ng_module_factory';
import {Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2} from '../render/api';
import {Sanitizer} from '../security';
import {Type} from '../type';
import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors';
import {resolveDep} from './provider';
import {dirtyParentQueries, getQueryValue} from './query';
import {createInjector} from './refs';
import {ArgumentType, BindingFlags, CheckType, DebugContext, ElementData, NodeDef, NodeFlags, NodeLogger, RootData, Services, ViewData, ViewDefinition, ViewState, asElementData, asPureExpressionData} from './types';
import {NOOP, isComponentView, renderNode, viewParentEl} from './util';
import {checkAndUpdateNode, checkAndUpdateView, checkNoChangesNode, checkNoChangesView, createEmbeddedView, createRootView, destroyView} from './view';
import {createInjector, createNgModuleRef} from './refs';
import {ArgumentType, BindingFlags, CheckType, DebugContext, DepDef, ElementData, NgModuleDefinition, NgModuleProviderDef, NodeDef, NodeFlags, NodeLogger, ProviderOverride, RootData, Services, ViewData, ViewDefinition, ViewState, asElementData, asPureExpressionData} from './types';
import {NOOP, isComponentView, renderNode, splitDepsDsl, viewParentEl} from './util';
import {checkAndUpdateNode, checkAndUpdateView, checkNoChangesNode, checkNoChangesView, createComponentView, createEmbeddedView, createRootView, destroyView} from './view';
let initialized = false;
@ -34,6 +35,10 @@ export function initServicesIfNeeded() {
Services.setCurrentNode = services.setCurrentNode;
Services.createRootView = services.createRootView;
Services.createEmbeddedView = services.createEmbeddedView;
Services.createComponentView = services.createComponentView;
Services.createNgModuleRef = services.createNgModuleRef;
Services.overrideProvider = services.overrideProvider;
Services.clearProviderOverrides = services.clearProviderOverrides;
Services.checkAndUpdateView = services.checkAndUpdateView;
Services.checkNoChangesView = services.checkNoChangesView;
Services.destroyView = services.destroyView;
@ -50,6 +55,10 @@ function createProdServices() {
setCurrentNode: () => {},
createRootView: createProdRootView,
createEmbeddedView: createEmbeddedView,
createComponentView: createComponentView,
createNgModuleRef: createNgModuleRef,
overrideProvider: NOOP,
clearProviderOverrides: NOOP,
checkAndUpdateView: checkAndUpdateView,
checkNoChangesView: checkNoChangesView,
destroyView: destroyView,
@ -72,13 +81,17 @@ function createDebugServices() {
setCurrentNode: debugSetCurrentNode,
createRootView: debugCreateRootView,
createEmbeddedView: debugCreateEmbeddedView,
createComponentView: debugCreateComponentView,
createNgModuleRef: debugCreateNgModuleRef,
overrideProvider: debugOverrideProvider,
clearProviderOverrides: debugClearProviderOverrides,
checkAndUpdateView: debugCheckAndUpdateView,
checkNoChangesView: debugCheckNoChangesView,
destroyView: debugDestroyView,
createDebugContext: (view: ViewData, nodeIndex: number) => new DebugContext_(view, nodeIndex),
handleEvent: debugHandleEvent,
updateDirectives: debugUpdateDirectives,
updateRenderer: debugUpdateRenderer
updateRenderer: debugUpdateRenderer,
};
}
@ -98,7 +111,9 @@ function debugCreateRootView(
const root = createRootData(
elInjector, ngModule, new DebugRendererFactory2(rendererFactory), projectableNodes,
rootSelectorOrNode);
return callWithDebugContext(DebugAction.create, createRootView, null, [root, def, context]);
const defWithOverride = applyProviderOverridesToView(def);
return callWithDebugContext(
DebugAction.create, createRootView, null, [root, defWithOverride, context]);
}
function createRootData(
@ -114,6 +129,136 @@ function createRootData(
};
}
function debugCreateEmbeddedView(
parentView: ViewData, anchorDef: NodeDef, viewDef: ViewDefinition, context?: any): ViewData {
const defWithOverride = applyProviderOverridesToView(viewDef);
return callWithDebugContext(
DebugAction.create, createEmbeddedView, null,
[parentView, anchorDef, defWithOverride, context]);
}
function debugCreateComponentView(
parentView: ViewData, nodeDef: NodeDef, viewDef: ViewDefinition, hostElement: any): ViewData {
const defWithOverride = applyProviderOverridesToView(viewDef);
return callWithDebugContext(
DebugAction.create, createComponentView, null,
[parentView, nodeDef, defWithOverride, hostElement]);
}
function debugCreateNgModuleRef(
moduleType: Type<any>, parentInjector: Injector, bootstrapComponents: Type<any>[],
def: NgModuleDefinition): NgModuleRef<any> {
const defWithOverride = applyProviderOverridesToNgModule(def);
return createNgModuleRef(moduleType, parentInjector, bootstrapComponents, defWithOverride);
}
const providerOverrides = new Map<any, ProviderOverride>();
function debugOverrideProvider(override: ProviderOverride) {
providerOverrides.set(override.token, override);
}
function debugClearProviderOverrides() {
providerOverrides.clear();
}
// Notes about the algorithm:
// 1) Locate the providers of an element and check if one of them was overwritten
// 2) Change the providers of that element
//
// We only create new datastructures if we need to, to keep perf impact
// reasonable.
function applyProviderOverridesToView(def: ViewDefinition): ViewDefinition {
if (providerOverrides.size === 0) {
return def;
}
const elementIndicesWithOverwrittenProviders = findElementIndicesWithOverwrittenProviders(def);
if (elementIndicesWithOverwrittenProviders.length === 0) {
return def;
}
// clone the whole view definition,
// as it maintains references between the nodes that are hard to update.
def = def.factory !(() => NOOP);
for (let i = 0; i < elementIndicesWithOverwrittenProviders.length; i++) {
applyProviderOverridesToElement(def, elementIndicesWithOverwrittenProviders[i]);
}
return def;
function findElementIndicesWithOverwrittenProviders(def: ViewDefinition): number[] {
const elIndicesWithOverwrittenProviders: number[] = [];
let lastElementDef: NodeDef|null = null;
for (let i = 0; i < def.nodes.length; i++) {
const nodeDef = def.nodes[i];
if (nodeDef.flags & NodeFlags.TypeElement) {
lastElementDef = nodeDef;
}
if (lastElementDef && nodeDef.flags & NodeFlags.CatProviderNoDirective &&
providerOverrides.has(nodeDef.provider !.token)) {
elIndicesWithOverwrittenProviders.push(lastElementDef !.index);
lastElementDef = null;
}
}
return elIndicesWithOverwrittenProviders;
}
function applyProviderOverridesToElement(viewDef: ViewDefinition, elIndex: number) {
for (let i = elIndex + 1; i < viewDef.nodes.length; i++) {
const nodeDef = viewDef.nodes[i];
if (nodeDef.flags & NodeFlags.TypeElement) {
// stop at the next element
return;
}
if (nodeDef.flags & NodeFlags.CatProviderNoDirective) {
// Make all providers lazy, so that we don't get into trouble
// with ordering problems of providers on the same element
nodeDef.flags |= NodeFlags.LazyProvider;
const provider = nodeDef.provider !;
const override = providerOverrides.get(provider.token);
if (override) {
nodeDef.flags = (nodeDef.flags & ~NodeFlags.CatProviderNoDirective) | override.flags;
provider.deps = splitDepsDsl(override.deps);
provider.value = override.value;
}
}
}
}
}
// Notes about the algorithm:
// We only create new datastructures if we need to, to keep perf impact
// reasonable.
function applyProviderOverridesToNgModule(def: NgModuleDefinition): NgModuleDefinition {
if (providerOverrides.size === 0 || !hasOverrrides(def)) {
return def;
}
// clone the whole view definition,
// as it maintains references between the nodes that are hard to update.
def = def.factory !(() => NOOP);
applyProviderOverrides(def);
return def;
function hasOverrrides(def: NgModuleDefinition): boolean {
return def.providers.some(
node =>
!!(node.flags & NodeFlags.CatProviderNoDirective) && providerOverrides.has(node.token));
}
function applyProviderOverrides(def: NgModuleDefinition) {
for (let i = 0; i < def.providers.length; i++) {
const provider = def.providers[i];
// Make all providers lazy, so that we don't get into trouble
// with ordering problems of providers on the same element
provider.flags |= NodeFlags.LazyProvider;
const override = providerOverrides.get(provider.token);
if (override) {
provider.flags = (provider.flags & ~NodeFlags.CatProviderNoDirective) | override.flags;
provider.deps = splitDepsDsl(override.deps);
provider.value = override.value;
}
}
}
}
function prodCheckAndUpdateNode(
view: ViewData, nodeIndex: number, argStyle: ArgumentType, v0?: any, v1?: any, v2?: any,
v3?: any, v4?: any, v5?: any, v6?: any, v7?: any, v8?: any, v9?: any): any {
@ -134,11 +279,6 @@ function prodCheckNoChangesNode(
undefined;
}
function debugCreateEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData {
return callWithDebugContext(
DebugAction.create, createEmbeddedView, null, [parent, anchorDef, context]);
}
function debugCheckAndUpdateView(view: ViewData) {
return callWithDebugContext(DebugAction.detectChanges, checkAndUpdateView, null, [view]);
}

View File

@ -14,6 +14,7 @@ import {TemplateRef} from '../linker/template_ref';
import {ViewContainerRef} from '../linker/view_container_ref';
import {Renderer2, RendererFactory2, RendererType2} from '../render/api';
import {Sanitizer, SecurityContext} from '../security';
import {Type} from '../type';
// -------------------------------------
// Defs
@ -169,8 +170,9 @@ export const enum NodeFlags {
PrivateProvider = 1 << 13,
TypeDirective = 1 << 14,
Component = 1 << 15,
CatProvider = TypeValueProvider | TypeClassProvider | TypeFactoryProvider |
TypeUseExistingProvider | TypeDirective,
CatProviderNoDirective =
TypeValueProvider | TypeClassProvider | TypeFactoryProvider | TypeUseExistingProvider,
CatProvider = CatProviderNoDirective | TypeDirective,
OnInit = 1 << 16,
OnDestroy = 1 << 17,
DoCheck = 1 << 18,
@ -495,12 +497,27 @@ export abstract class DebugContext {
export const enum CheckType {CheckAndUpdate, CheckNoChanges}
export interface ProviderOverride {
token: any;
flags: NodeFlags;
value: any;
deps: ([DepFlags, any]|any)[];
}
export interface Services {
setCurrentNode(view: ViewData, nodeIndex: number): void;
createRootView(
injector: Injector, projectableNodes: any[][], rootSelectorOrNode: string|any,
def: ViewDefinition, ngModule: NgModuleRef<any>, context?: any): ViewData;
createEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData;
createEmbeddedView(parent: ViewData, anchorDef: NodeDef, viewDef: ViewDefinition, context?: any):
ViewData;
createComponentView(
parentView: ViewData, nodeDef: NodeDef, viewDef: ViewDefinition, hostElement: any): ViewData;
createNgModuleRef(
moduleType: Type<any>, parent: Injector, bootstrapComponents: Type<any>[],
def: NgModuleDefinition): NgModuleRef<any>;
overrideProvider(override: ProviderOverride): void;
clearProviderOverrides(): void;
checkAndUpdateView(view: ViewData): void;
checkNoChangesView(view: ViewData): void;
destroyView(view: ViewData): void;
@ -522,6 +539,10 @@ export const Services: Services = {
setCurrentNode: undefined !,
createRootView: undefined !,
createEmbeddedView: undefined !,
createComponentView: undefined !,
createNgModuleRef: undefined !,
overrideProvider: undefined !,
clearProviderOverrides: undefined !,
checkAndUpdateView: undefined !,
checkNoChangesView: undefined !,
destroyView: undefined !,

View File

@ -12,7 +12,7 @@ import {RendererType2} from '../render/api';
import {looseIdentical, stringify} from '../util';
import {expressionChangedAfterItHasBeenCheckedError} from './errors';
import {BindingDef, BindingFlags, Definition, DefinitionFactory, ElementData, NodeDef, NodeFlags, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewState, asElementData, asTextData} from './types';
import {BindingDef, BindingFlags, Definition, DefinitionFactory, DepDef, DepFlags, ElementData, NodeDef, NodeFlags, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewState, asElementData, asTextData} from './types';
export const NOOP: any = () => {};
@ -203,6 +203,20 @@ export function splitMatchedQueriesDsl(
return {matchedQueries, references, matchedQueryIds};
}
export function splitDepsDsl(deps: ([DepFlags, any] | any)[]): DepDef[] {
return deps.map(value => {
let token: any;
let flags: DepFlags;
if (Array.isArray(value)) {
[flags, token] = value;
} else {
flags = DepFlags.None;
token = value;
}
return {flags, token, tokenKey: tokenKey(token)};
});
}
export function getParentRenderElement(view: ViewData, renderHost: any, def: NodeDef): any {
let renderParent = def.renderParent;
if (renderParent) {

View File

@ -184,11 +184,11 @@ function validateNode(parent: NodeDef | null, node: NodeDef, nodeCount: number)
}
}
export function createEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData {
export function createEmbeddedView(
parent: ViewData, anchorDef: NodeDef, viewDef: ViewDefinition, context?: any): ViewData {
// embedded views are seen as siblings to the anchor, so we need
// to get the parent of the anchor and use it as parentIndex.
const view =
createView(parent.root, parent.renderer, parent, anchorDef, anchorDef.element !.template !);
const view = createView(parent.root, parent.renderer, parent, anchorDef, viewDef);
initView(view, parent.component, context);
createViewNodes(view);
return view;
@ -201,6 +201,19 @@ export function createRootView(root: RootData, def: ViewDefinition, context?: an
return view;
}
export function createComponentView(
parentView: ViewData, nodeDef: NodeDef, viewDef: ViewDefinition, hostElement: any): ViewData {
const rendererType = nodeDef.element !.componentRendererType;
let compRenderer: Renderer2;
if (!rendererType) {
compRenderer = parentView.root.renderer;
} else {
compRenderer = parentView.root.rendererFactory.createRenderer(hostElement, rendererType);
}
return createView(
parentView.root, compRenderer, parentView, nodeDef.element !.componentProvider, viewDef);
}
function createView(
root: RootData, renderer: Renderer2, parent: ViewData | null, parentNodeDef: NodeDef | null,
def: ViewDefinition): ViewData {
@ -241,15 +254,7 @@ function createViewNodes(view: ViewData) {
let componentView: ViewData = undefined !;
if (nodeDef.flags & NodeFlags.ComponentView) {
const compViewDef = resolveDefinition(nodeDef.element !.componentView !);
const rendererType = nodeDef.element !.componentRendererType;
let compRenderer: Renderer2;
if (!rendererType) {
compRenderer = view.root.renderer;
} else {
compRenderer = view.root.rendererFactory.createRenderer(el, rendererType);
}
componentView = createView(
view.root, compRenderer, view, nodeDef.element !.componentProvider, compViewDef);
componentView = Services.createComponentView(view, nodeDef, compViewDef, el);
}
listenToElementOutputs(view, componentView, nodeDef, el);
nodeData = <ElementData>{