feat(ivy): add support of ApplicationRef.bootstrapModuleFactory (#23811)

PR Close #23811
This commit is contained in:
Jason Aden 2018-05-09 16:49:39 -07:00 committed by Miško Hevery
parent 7de2ba0e22
commit e3759f7a73
29 changed files with 589 additions and 156 deletions

View File

@ -10,11 +10,15 @@ import {APP_INITIALIZER, ApplicationInitStatus} from './application_init';
import {ApplicationRef} from './application_ref'; import {ApplicationRef} from './application_ref';
import {APP_ID_RANDOM_PROVIDER} from './application_tokens'; import {APP_ID_RANDOM_PROVIDER} from './application_tokens';
import {IterableDiffers, KeyValueDiffers, defaultIterableDiffers, defaultKeyValueDiffers} from './change_detection/change_detection'; import {IterableDiffers, KeyValueDiffers, defaultIterableDiffers, defaultKeyValueDiffers} from './change_detection/change_detection';
import {forwardRef} from './di/forward_ref'; import {Console} from './console';
import {InjectionToken, Injector, StaticProvider} from './di';
import {Inject, Optional, SkipSelf} from './di/metadata'; import {Inject, Optional, SkipSelf} from './di/metadata';
import {ErrorHandler} from './error_handler';
import {LOCALE_ID} from './i18n/tokens'; import {LOCALE_ID} from './i18n/tokens';
import {ComponentFactoryResolver} from './linker';
import {Compiler} from './linker/compiler'; import {Compiler} from './linker/compiler';
import {NgModule} from './metadata'; import {NgModule} from './metadata';
import {NgZone} from './zone';
export function _iterableDiffersFactory() { export function _iterableDiffersFactory() {
return defaultIterableDiffers; return defaultIterableDiffers;
@ -28,27 +32,36 @@ export function _localeFactory(locale?: string): string {
return locale || 'en-US'; return locale || 'en-US';
} }
export const APPLICATION_MODULE_PROVIDERS: StaticProvider[] = [
{
provide: ApplicationRef,
useClass: ApplicationRef,
deps:
[NgZone, Console, Injector, ErrorHandler, ComponentFactoryResolver, ApplicationInitStatus]
},
{
provide: ApplicationInitStatus,
useClass: ApplicationInitStatus,
deps: [[new Optional(), APP_INITIALIZER]]
},
{provide: Compiler, useClass: Compiler, deps: []},
APP_ID_RANDOM_PROVIDER,
{provide: IterableDiffers, useFactory: _iterableDiffersFactory, deps: []},
{provide: KeyValueDiffers, useFactory: _keyValueDiffersFactory, deps: []},
{
provide: LOCALE_ID,
useFactory: _localeFactory,
deps: [[new Inject(LOCALE_ID), new Optional(), new SkipSelf()]]
},
];
/** /**
* This module includes the providers of @angular/core that are needed * This module includes the providers of @angular/core that are needed
* to bootstrap components via `ApplicationRef`. * to bootstrap components via `ApplicationRef`.
* *
* @experimental * @experimental
*/ */
@NgModule({ @NgModule({providers: APPLICATION_MODULE_PROVIDERS})
providers: [
ApplicationRef,
ApplicationInitStatus,
Compiler,
APP_ID_RANDOM_PROVIDER,
{provide: IterableDiffers, useFactory: _iterableDiffersFactory},
{provide: KeyValueDiffers, useFactory: _keyValueDiffersFactory},
{
provide: LOCALE_ID,
useFactory: _localeFactory,
deps: [[new Inject(LOCALE_ID), new Optional(), new SkipSelf()]]
},
],
})
export class ApplicationModule { export class ApplicationModule {
// Inject ApplicationRef to make it eager... // Inject ApplicationRef to make it eager...
constructor(appRef: ApplicationRef) {} constructor(appRef: ApplicationRef) {}

View File

@ -23,6 +23,8 @@ export {
injectAttribute as ɵinjectAttribute, injectAttribute as ɵinjectAttribute,
PublicFeature as ɵPublicFeature, PublicFeature as ɵPublicFeature,
NgOnChangesFeature as ɵNgOnChangesFeature, NgOnChangesFeature as ɵNgOnChangesFeature,
NgModuleDef as ɵNgModuleDef,
NgModuleType as ɵNgModuleType,
CssSelectorList as ɵCssSelectorList, CssSelectorList as ɵCssSelectorList,
markDirty as ɵmarkDirty, markDirty as ɵmarkDirty,
NC as ɵNC, NC as ɵNC,

View File

@ -18,7 +18,7 @@ export {forwardRef, resolveForwardRef, ForwardRefFn} from './di/forward_ref';
export {Injectable, InjectableDecorator, InjectableProvider} from './di/injectable'; export {Injectable, InjectableDecorator, InjectableProvider} from './di/injectable';
export {inject, InjectFlags, INJECTOR, Injector} from './di/injector'; export {inject, InjectFlags, INJECTOR, Injector} from './di/injector';
export {ReflectiveInjector} from './di/reflective_injector'; export {ReflectiveInjector} from './di/reflective_injector';
export {StaticProvider, ValueProvider, ExistingProvider, FactoryProvider, Provider, TypeProvider, ClassProvider} from './di/provider'; export {StaticProvider, ValueProvider, ConstructorSansProvider, ExistingProvider, FactoryProvider, Provider, TypeProvider, ClassProvider} from './di/provider';
export {createInjector} from './di/r3_injector'; export {createInjector} from './di/r3_injector';
export {ResolvedReflectiveFactory, ResolvedReflectiveProvider} from './di/reflective_provider'; export {ResolvedReflectiveFactory, ResolvedReflectiveProvider} from './di/reflective_provider';
export {ReflectiveKey} from './di/reflective_key'; export {ReflectiveKey} from './di/reflective_key';

View File

@ -32,6 +32,9 @@ export const INJECTOR = new InjectionToken<Injector>('INJECTOR');
export class NullInjector implements Injector { export class NullInjector implements Injector {
get(token: any, notFoundValue: any = _THROW_IF_NOT_FOUND): any { get(token: any, notFoundValue: any = _THROW_IF_NOT_FOUND): any {
if (notFoundValue === _THROW_IF_NOT_FOUND) { if (notFoundValue === _THROW_IF_NOT_FOUND) {
// Intentionally left behind: With dev tools open the debugger will stop here. There is no
// reason why correctly written application should cause this exception.
debugger;
throw new Error(`NullInjectorError: No provider for ${stringify(token)}!`); throw new Error(`NullInjectorError: No provider for ${stringify(token)}!`);
} }
return notFoundValue; return notFoundValue;
@ -487,11 +490,11 @@ export function injectArgs(types: (Type<any>| InjectionToken<any>| any[])[]): an
for (let j = 0; j < arg.length; j++) { for (let j = 0; j < arg.length; j++) {
const meta = arg[j]; const meta = arg[j];
if (meta instanceof Optional || meta.__proto__.ngMetadataName === 'Optional') { if (meta instanceof Optional || meta.ngMetadataName === 'Optional') {
flags |= InjectFlags.Optional; flags |= InjectFlags.Optional;
} else if (meta instanceof SkipSelf || meta.__proto__.ngMetadataName === 'SkipSelf') { } else if (meta instanceof SkipSelf || meta.ngMetadataName === 'SkipSelf') {
flags |= InjectFlags.SkipSelf; flags |= InjectFlags.SkipSelf;
} else if (meta instanceof Self || meta.__proto__.ngMetadataName === 'Self') { } else if (meta instanceof Self || meta.ngMetadataName === 'Self') {
flags |= InjectFlags.Self; flags |= InjectFlags.Self;
} else if (meta instanceof Inject) { } else if (meta instanceof Inject) {
type = meta.token; type = meta.token;

View File

@ -151,10 +151,6 @@ export interface StaticClassProvider extends StaticClassSansProvider {
* *
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}. * For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
* *
* ### Example
*
* {@example core/di/ts/provider_spec.ts region='ConstructorSansProvider'}
*
* @experimental * @experimental
*/ */
export interface ConstructorSansProvider { export interface ConstructorSansProvider {
@ -453,5 +449,5 @@ export interface ClassProvider extends ClassSansProvider {
* *
* *
*/ */
export type Provider = export type Provider = TypeProvider | ValueProvider | ClassProvider | ConstructorProvider |
TypeProvider | ValueProvider | ClassProvider | ExistingProvider | FactoryProvider | any[]; ExistingProvider | FactoryProvider | any[];

View File

@ -14,7 +14,7 @@ import {InjectableDef, InjectableType, InjectorDef, InjectorType, InjectorTypeWi
import {resolveForwardRef} from './forward_ref'; import {resolveForwardRef} from './forward_ref';
import {InjectableDefToken, InjectionToken} from './injection_token'; import {InjectableDefToken, InjectionToken} from './injection_token';
import {INJECTOR, InjectFlags, Injector, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE, inject, injectArgs, setCurrentInjector} from './injector'; import {INJECTOR, InjectFlags, Injector, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE, inject, injectArgs, setCurrentInjector} from './injector';
import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, Provider, StaticClassProvider, TypeProvider, ValueProvider} from './provider'; import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, Provider, StaticClassProvider, StaticProvider, TypeProvider, ValueProvider} from './provider';
import {APP_ROOT} from './scope'; import {APP_ROOT} from './scope';
@ -64,14 +64,15 @@ interface Record<T> {
} }
/** /**
* Create a new `Injector` which is configured using `InjectorType`s. * Create a new `Injector` which is configured using a `defType` of `InjectorType<any>`s.
* *
* @experimental * @experimental
*/ */
export function createInjector( export function createInjector(
defType: /* InjectorType<any> */ any, parent: Injector | null = null): Injector { defType: /* InjectorType<any> */ any, parent: Injector | null = null,
additionalProviders: StaticProvider[] | null = null): Injector {
parent = parent || getNullInjector(); parent = parent || getNullInjector();
return new R3Injector(defType, parent); return new R3Injector(defType, additionalProviders, parent);
} }
export class R3Injector { export class R3Injector {
@ -101,12 +102,18 @@ export class R3Injector {
*/ */
private destroyed = false; private destroyed = false;
constructor(def: InjectorType<any>, readonly parent: Injector) { constructor(
def: InjectorType<any>, additionalProviders: StaticProvider[]|null,
readonly parent: Injector) {
// Start off by creating Records for every provider declared in every InjectorType // Start off by creating Records for every provider declared in every InjectorType
// included transitively in `def`. // included transitively in `def`.
deepForEach( deepForEach(
[def], injectorDef => this.processInjectorType(injectorDef, new Set<InjectorType<any>>())); [def], injectorDef => this.processInjectorType(injectorDef, new Set<InjectorType<any>>()));
additionalProviders &&
deepForEach(additionalProviders, provider => this.processProvider(provider));
// Make sure the INJECTOR token provides this injector. // Make sure the INJECTOR token provides this injector.
this.records.set(INJECTOR, makeRecord(undefined, this)); this.records.set(INJECTOR, makeRecord(undefined, this));
@ -284,20 +291,18 @@ export class R3Injector {
throw new Error(`Mixed multi-provider for ${token}.`); throw new Error(`Mixed multi-provider for ${token}.`);
} }
} else { } else {
token = provider;
multiRecord = makeRecord(undefined, NOT_YET, true); multiRecord = makeRecord(undefined, NOT_YET, true);
multiRecord.factory = () => injectArgs(multiRecord !.multi !); multiRecord.factory = () => injectArgs(multiRecord !.multi !);
this.records.set(token, multiRecord); this.records.set(token, multiRecord);
} }
token = provider; token = provider;
multiRecord.multi !.push(provider); multiRecord.multi !.push(provider);
} } else {
const existing = this.records.get(token); const existing = this.records.get(token);
if (existing && existing.multi !== undefined) { if (existing && existing.multi !== undefined) {
throw new Error(`Mixed multi-provider for ${token}`); throw new Error(`Mixed multi-provider for ${stringify(token)}`);
}
} }
this.records.set(token, record); this.records.set(token, record);
} }

View File

@ -46,13 +46,13 @@ export function assertGreaterThan<T>(actual: T, expected: T, msg: string) {
} }
} }
export function assertNull<T>(actual: T, msg: string) { export function assertNotDefined<T>(actual: T, msg: string) {
if (actual != null) { if (actual != null) {
throwError(msg); throwError(msg);
} }
} }
export function assertNotNull<T>(actual: T, msg: string) { export function assertDefined<T>(actual: T, msg: string) {
if (actual == null) { if (actual == null) {
throwError(msg); throwError(msg);
} }

View File

@ -13,7 +13,7 @@ import {Injector} from '../di/injector';
import {ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory'; import {ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
import {Sanitizer} from '../sanitization/security'; import {Sanitizer} from '../sanitization/security';
import {assertComponentType, assertNotNull} from './assert'; import {assertComponentType, assertDefined} from './assert';
import {queueInitHooks, queueLifecycleHooks} from './hooks'; import {queueInitHooks, queueLifecycleHooks} from './hooks';
import {CLEAN_PROMISE, ROOT_DIRECTIVE_INDICES, _getComponentHostLElementNode, baseDirectiveCreate, createLView, createTView, detectChangesInternal, enterView, executeInitAndContentHooks, getRootView, hostElement, initChangeDetectorIfExisting, leaveView, locateHostElement, setHostBindings} from './instructions'; import {CLEAN_PROMISE, ROOT_DIRECTIVE_INDICES, _getComponentHostLElementNode, baseDirectiveCreate, createLView, createTView, detectChangesInternal, enterView, executeInitAndContentHooks, getRootView, hostElement, initChangeDetectorIfExisting, leaveView, locateHostElement, setHostBindings} from './instructions';
import {ComponentDef, ComponentType} from './interfaces/definition'; import {ComponentDef, ComponentType} from './interfaces/definition';
@ -72,31 +72,6 @@ export interface CreateComponentOptions {
} }
/**
* Bootstraps a component, then creates and returns a `ComponentRef` for that component.
*
* @param componentType Component to bootstrap
* @param options Optional parameters which control bootstrapping
*/
export function createComponentRef<T>(
componentType: ComponentType<T>, opts: CreateComponentOptions): viewEngine_ComponentRef<T> {
const component = renderComponent(componentType, opts);
const hostView = _getComponentHostLElementNode(component).data as LView;
const hostViewRef = new ViewRef(hostView, component);
return {
location: {nativeElement: getHostElement(component)},
injector: opts.injector || NULL_INJECTOR,
instance: component,
hostView: hostViewRef,
changeDetectorRef: hostViewRef,
componentType: componentType,
// TODO: implement destroy and onDestroy
destroy: () => {},
onDestroy: (cb: Function) => {}
};
}
// TODO: A hack to not pull in the NullInjector from @angular/core. // TODO: A hack to not pull in the NullInjector from @angular/core.
export const NULL_INJECTOR: Injector = { export const NULL_INJECTOR: Injector = {
get: (token: any, notFoundValue?: any) => { get: (token: any, notFoundValue?: any) => {
@ -131,12 +106,8 @@ export function renderComponent<T>(
// The first index of the first selector is the tag name. // The first index of the first selector is the tag name.
const componentTag = componentDef.selectors ![0] ![0] as string; const componentTag = componentDef.selectors ![0] ![0] as string;
const hostNode = locateHostElement(rendererFactory, opts.host || componentTag); const hostNode = locateHostElement(rendererFactory, opts.host || componentTag);
const rootContext: RootContext = { const rootContext = createRootContext(opts.scheduler || requestAnimationFrame.bind(window));
// Incomplete initialization due to circular reference.
component: null !,
scheduler: opts.scheduler || requestAnimationFrame.bind(window),
clean: CLEAN_PROMISE,
};
const rootView: LView = createLView( const rootView: LView = createLView(
rendererFactory.createRenderer(hostNode, componentDef.rendererType), rendererFactory.createRenderer(hostNode, componentDef.rendererType),
createTView(-1, null, null, null), rootContext, createTView(-1, null, null, null), rootContext,
@ -152,8 +123,8 @@ export function renderComponent<T>(
elementNode = hostElement(componentTag, hostNode, componentDef, sanitizer); elementNode = hostElement(componentTag, hostNode, componentDef, sanitizer);
// Create directive instance with factory() and store at index 0 in directives array // Create directive instance with factory() and store at index 0 in directives array
component = rootContext.component = rootContext.components.push(
baseDirectiveCreate(0, componentDef.factory(), componentDef) as T; component = baseDirectiveCreate(0, componentDef.factory(), componentDef) as T);
initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data !); initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data !);
opts.hostFeatures && opts.hostFeatures.forEach((feature) => feature(component, componentDef)); opts.hostFeatures && opts.hostFeatures.forEach((feature) => feature(component, componentDef));
@ -169,6 +140,14 @@ export function renderComponent<T>(
return component; return component;
} }
export function createRootContext(scheduler: (workFn: () => void) => void): RootContext {
return {
components: [],
scheduler: scheduler,
clean: CLEAN_PROMISE,
};
}
/** /**
* Used to enable lifecycle hooks on the root component. * Used to enable lifecycle hooks on the root component.
* *
@ -198,7 +177,7 @@ export function LifecycleHooksFeature(component: any, def: ComponentDef<any>): v
*/ */
function getRootContext(component: any): RootContext { function getRootContext(component: any): RootContext {
const rootContext = getRootView(component).context as RootContext; const rootContext = getRootView(component).context as RootContext;
ngDevMode && assertNotNull(rootContext, 'rootContext'); ngDevMode && assertDefined(rootContext, 'rootContext');
return rootContext; return rootContext;
} }

View File

@ -0,0 +1,176 @@
/**
* @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 {ChangeDetectorRef} from '../change_detection/change_detector_ref';
import {InjectionToken} from '../di/injection_token';
import {Injector, inject} from '../di/injector';
import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '../linker/component_factory_resolver';
import {ElementRef} from '../linker/element_ref';
import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory';
import {RendererFactory2} from '../render/api';
import {Type} from '../type';
import {assertComponentType, assertDefined} from './assert';
import {createRootContext} from './component';
import {baseDirectiveCreate, createLView, createTView, enterView, hostElement, initChangeDetectorIfExisting, leaveView, locateHostElement} from './instructions';
import {ComponentDef, ComponentType} from './interfaces/definition';
import {LElementNode} from './interfaces/node';
import {RElement} from './interfaces/renderer';
import {LView, LViewFlags, RootContext} from './interfaces/view';
import {ViewRef} from './view_ref';
export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolver {
resolveComponentFactory<T>(component: Type<T>): viewEngine_ComponentFactory<T> {
ngDevMode && assertComponentType(component);
const componentDef = (component as ComponentType<T>).ngComponentDef;
return new ComponentFactory(componentDef);
}
}
function toRefArray(map: {[key: string]: string}): {propName: string; templateName: string;}[] {
const array: {propName: string; templateName: string;}[] = [];
for (let nonMinified in map) {
if (map.hasOwnProperty(nonMinified)) {
const minified = map[nonMinified];
array.push({propName: minified, templateName: nonMinified});
}
}
return array;
}
/**
* Default {@link RootContext} for all components rendered with {@link renderComponent}.
*/
export const ROOT_CONTEXT = new InjectionToken<RootContext>(
'ROOT_CONTEXT_TOKEN',
{providedIn: 'root', factory: () => createRootContext(inject(SCHEDULER))});
/**
* A change detection scheduler token for {@link RootContext}. This token is the default value used
* for the default `RootContext` found in the {@link ROOT_CONTEXT} token.
*/
export const SCHEDULER = new InjectionToken<((fn: () => void) => void)>(
'SCHEDULER_TOKEN', {providedIn: 'root', factory: () => requestAnimationFrame.bind(window)});
/**
* Render3 implementation of {@link viewEngine_ComponentFactory}.
*/
export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
selector: string;
componentType: Type<any>;
ngContentSelectors: string[];
get inputs(): {propName: string; templateName: string;}[] {
return toRefArray(this.componentDef.inputs);
}
get outputs(): {propName: string; templateName: string;}[] {
return toRefArray(this.componentDef.outputs);
}
constructor(private componentDef: ComponentDef<any>) {
super();
this.componentType = componentDef.type;
this.selector = componentDef.selectors[0][0] as string;
this.ngContentSelectors = [];
}
create(
parentComponentInjector: Injector, projectableNodes?: any[][]|undefined,
rootSelectorOrNode?: any,
ngModule?: viewEngine_NgModuleRef<any>|undefined): viewEngine_ComponentRef<T> {
ngDevMode && assertDefined(ngModule, 'ngModule should always be defined');
const rendererFactory = ngModule ? ngModule.injector.get(RendererFactory2) : document;
const hostNode = locateHostElement(rendererFactory, rootSelectorOrNode);
// The first index of the first selector is the tag name.
const componentTag = this.componentDef.selectors ![0] ![0] as string;
const rootContext: RootContext = ngModule !.injector.get(ROOT_CONTEXT);
// Create the root view. Uses empty TView and ContentTemplate.
const rootView: LView = createLView(
rendererFactory.createRenderer(hostNode, this.componentDef.rendererType),
createTView(-1, null, null, null), null,
this.componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways);
rootView.injector = ngModule && ngModule.injector || null;
// rootView is the parent when bootstrapping
const oldView = enterView(rootView, null !);
let component: T;
let elementNode: LElementNode;
try {
if (rendererFactory.begin) rendererFactory.begin();
// Create element node at index 0 in data array
elementNode = hostElement(componentTag, hostNode, this.componentDef);
// Create directive instance with factory() and store at index 0 in directives array
rootContext.components.push(
component = baseDirectiveCreate(0, this.componentDef.factory(), this.componentDef) as T);
initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data !);
} finally {
enterView(oldView, null);
if (rendererFactory.end) rendererFactory.end();
}
// TODO(misko): this is the wrong injector here.
return new ComponentRef(
this.componentType, component, rootView, ngModule !.injector, hostNode !);
}
}
/**
* Represents an instance of a Component created via a {@link ComponentFactory}.
*
* `ComponentRef` provides access to the Component Instance as well other objects related to this
* Component Instance and allows you to destroy the Component Instance via the {@link #destroy}
* method.
*
*/
export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
destroyCbs: (() => void)[]|null = [];
location: ElementRef<any>;
injector: Injector;
instance: T;
hostView: ViewRef<T>;
changeDetectorRef: ChangeDetectorRef;
componentType: Type<T>;
constructor(
componentType: Type<T>, instance: T, rootView: LView, injector: Injector,
hostNode: RElement) {
super();
this.instance = instance;
/* TODO(jasonaden): This is incomplete, to be adjusted in follow-up PR. Notes from Kara:When
* ViewRef.detectChanges is called from ApplicationRef.tick, it will call detectChanges at the
* component instance level. I suspect this means that lifecycle hooks and host bindings on the
* given component won't work (as these are always called at the level above a component).
*
* In render2, ViewRef.detectChanges uses the root view instance for view checks, not the
* component instance. So passing in the root view (1 level above the component) is sufficient.
* We might want to think about creating a fake component for the top level? Or overwrite
* detectChanges with a function that calls tickRootContext? */
this.hostView = this.changeDetectorRef = new ViewRef(rootView, instance);
this.injector = injector;
this.location = new ElementRef(hostNode);
this.componentType = componentType;
}
destroy(): void {
ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
this.destroyCbs !.forEach(fn => fn());
this.destroyCbs = null;
}
onDestroy(callback: () => void): void {
ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
this.destroyCbs !.push(callback);
}
}

View File

@ -18,9 +18,9 @@ import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_co
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref'; import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref';
import {Type} from '../type'; import {Type} from '../type';
import {assertGreaterThan, assertLessThan, assertNotNull} from './assert'; import {assertDefined, assertGreaterThan, assertLessThan} from './assert';
import {addToViewTree, assertPreviousIsParent, createLContainer, createLNodeObject, createTNode, createTView, getDirectiveInstance, getPreviousOrParentNode, getRenderer, isComponent, renderEmbeddedTemplate, resolveDirective} from './instructions'; import {addToViewTree, assertPreviousIsParent, createLContainer, createLNodeObject, createTNode, createTView, getDirectiveInstance, getPreviousOrParentNode, getRenderer, isComponent, renderEmbeddedTemplate, resolveDirective} from './instructions';
import {ComponentTemplate, DirectiveDef} from './interfaces/definition'; import {ComponentTemplate, DirectiveDef, DirectiveDefList, PipeDefList} from './interfaces/definition';
import {LInjector} from './interfaces/injector'; import {LInjector} from './interfaces/injector';
import {AttributeMarker, LContainerNode, LElementNode, LNode, LViewNode, TNodeFlags, TNodeType} from './interfaces/node'; import {AttributeMarker, LContainerNode, LElementNode, LNode, LViewNode, TNodeFlags, TNodeType} from './interfaces/node';
import {LQueries, QueryReadType} from './interfaces/query'; import {LQueries, QueryReadType} from './interfaces/query';
@ -256,7 +256,7 @@ export function injectAttribute(attrNameToInject: string): string|undefined {
const lElement = getPreviousOrParentNode() as LElementNode; const lElement = getPreviousOrParentNode() as LElementNode;
ngDevMode && assertNodeType(lElement, TNodeType.Element); ngDevMode && assertNodeType(lElement, TNodeType.Element);
const tElement = lElement.tNode; const tElement = lElement.tNode;
ngDevMode && assertNotNull(tElement, 'expecting tNode'); ngDevMode && assertDefined(tElement, 'expecting tNode');
const attrs = tElement.attrs; const attrs = tElement.attrs;
if (attrs) { if (attrs) {
for (let i = 0; i < attrs.length; i = i + 2) { for (let i = 0; i < attrs.length; i = i + 2) {
@ -707,7 +707,7 @@ export function getOrCreateTemplateRef<T>(di: LInjector): viewEngine_TemplateRef
hostTNode.tViews = createTView( hostTNode.tViews = createTView(
-1, hostNode.data.template !, hostTView.directiveRegistry, hostTView.pipeRegistry); -1, hostNode.data.template !, hostTView.directiveRegistry, hostTView.pipeRegistry);
} }
ngDevMode && assertNotNull(hostTNode.tViews, 'TView must be allocated'); ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated');
di.templateRef = new TemplateRef<any>( di.templateRef = new TemplateRef<any>(
getOrCreateElementRef(di), hostTNode.tViews as TView, getRenderer(), hostNode.data.queries); getOrCreateElementRef(di), hostTNode.tViews as TView, getRenderer(), hostNode.data.queries);
} }

View File

@ -6,16 +6,16 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {LifecycleHooksFeature, createComponentRef, getHostElement, getRenderedText, renderComponent, whenRendered} from './component'; import {LifecycleHooksFeature, getHostElement, getRenderedText, renderComponent, whenRendered} from './component';
import {NgOnChangesFeature, PublicFeature, defineComponent, defineDirective, definePipe} from './definition'; import {NgOnChangesFeature, PublicFeature, defineComponent, defineDirective, definePipe} from './definition';
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveType, PipeDef} from './interfaces/definition'; import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveType, PipeDef} from './interfaces/definition';
export {ComponentFactory, ComponentFactoryResolver, ComponentRef} from './component_ref';
export {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, injectAttribute, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di'; export {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, injectAttribute, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di';
export {RenderFlags} from './interfaces/definition'; export {RenderFlags} from './interfaces/definition';
export {CssSelectorList} from './interfaces/projection'; export {CssSelectorList} from './interfaces/projection';
// Naming scheme: // Naming scheme:
// - Capital letters are for creating things: T(Text), E(Element), D(Directive), V(View), // - Capital letters are for creating things: T(Text), E(Element), D(Directive), V(View),
// C(Container), L(Listener) // C(Container), L(Listener)
@ -73,6 +73,8 @@ export {
tick, tick,
} from './instructions'; } from './instructions';
export {NgModuleDef, NgModuleFactory, NgModuleRef, NgModuleType} from './ng_module_ref';
export { export {
AttributeMarker AttributeMarker
} from './interfaces/node'; } from './interfaces/node';
@ -122,7 +124,6 @@ export {
defineComponent, defineComponent,
defineDirective, defineDirective,
definePipe, definePipe,
createComponentRef,
getHostElement, getHostElement,
getRenderedText, getRenderedText,
renderComponent, renderComponent,

View File

@ -8,7 +8,11 @@
import './ng_dev_mode'; import './ng_dev_mode';
import {assertEqual, assertLessThan, assertNotEqual, assertNotNull, assertNull, assertSame} from './assert'; import {Sanitizer} from '../sanitization/security';
import {assertDefined, assertEqual, assertLessThan, assertNotDefined, assertNotEqual, assertSame} from './assert';
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
import {LContainer} from './interfaces/container'; import {LContainer} from './interfaces/container';
import {LInjector} from './interfaces/injector'; import {LInjector} from './interfaces/injector';
import {CssSelectorList, LProjection, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection'; import {CssSelectorList, LProjection, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
@ -22,10 +26,7 @@ import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, PipeDefList, PipeDefListOrFactory, RenderFlags} from './interfaces/definition'; import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, PipeDefList, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer'; import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
import {isDifferent, stringify} from './util'; import {isDifferent, stringify} from './util';
import {executeHooks, queueLifecycleHooks, queueInitHooks, executeInitHooks} from './hooks';
import {ViewRef} from './view_ref'; import {ViewRef} from './view_ref';
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
import {Sanitizer} from '../sanitization/security';
/** /**
* Directive (D) sets a property on all component instances using this constant as a key and the * Directive (D) sets a property on all component instances using this constant as a key and the
@ -406,7 +407,8 @@ export function createLNode(
if ((type & TNodeType.ViewOrElement) === TNodeType.ViewOrElement && isState) { if ((type & TNodeType.ViewOrElement) === TNodeType.ViewOrElement && isState) {
// Bit of a hack to bust through the readonly because there is a circular dep between // Bit of a hack to bust through the readonly because there is a circular dep between
// LView and LNode. // LView and LNode.
ngDevMode && assertNull((state as LView).node, 'LView.node should not have been initialized'); ngDevMode &&
assertNotDefined((state as LView).node, 'LView.node should not have been initialized');
(state as{node: LNode}).node = node; (state as{node: LNode}).node = node;
if (firstTemplatePass) (state as LView).tView.node = node.tNode; if (firstTemplatePass) (state as LView).tView.node = node.tNode;
} }
@ -455,7 +457,7 @@ export function renderTemplate<T>(
sanitizer)); sanitizer));
} }
const hostView = host.data !; const hostView = host.data !;
ngDevMode && assertNotNull(hostView, 'Host node should have an LView defined in host.data.'); ngDevMode && assertDefined(hostView, 'Host node should have an LView defined in host.data.');
renderComponentOrTemplate(host, hostView, context, template); renderComponentOrTemplate(host, hostView, context, template);
return host; return host;
} }
@ -1300,8 +1302,8 @@ export function textBinding<T>(index: number, value: T | NO_CHANGE): void {
if (value !== NO_CHANGE) { if (value !== NO_CHANGE) {
ngDevMode && assertDataInRange(index); ngDevMode && assertDataInRange(index);
const existingNode = data[index] as LTextNode; const existingNode = data[index] as LTextNode;
ngDevMode && assertNotNull(existingNode, 'LNode should exist'); ngDevMode && assertDefined(existingNode, 'LNode should exist');
ngDevMode && assertNotNull(existingNode.native, 'native element should exist'); ngDevMode && assertDefined(existingNode.native, 'native element should exist');
ngDevMode && ngDevMode.rendererSetText++; ngDevMode && ngDevMode.rendererSetText++;
isProceduralRenderer(renderer) ? renderer.setValue(existingNode.native, stringify(value)) : isProceduralRenderer(renderer) ? renderer.setValue(existingNode.native, stringify(value)) :
existingNode.native.textContent = stringify(value); existingNode.native.textContent = stringify(value);
@ -1325,7 +1327,7 @@ export function directiveCreate<T>(
index: number, directive: T, directiveDef: DirectiveDef<T>| ComponentDef<T>): T { index: number, directive: T, directiveDef: DirectiveDef<T>| ComponentDef<T>): T {
const instance = baseDirectiveCreate(index, directive, directiveDef); const instance = baseDirectiveCreate(index, directive, directiveDef);
ngDevMode && assertNotNull(previousOrParentNode.tNode, 'previousOrParentNode.tNode'); ngDevMode && assertDefined(previousOrParentNode.tNode, 'previousOrParentNode.tNode');
const tNode = previousOrParentNode.tNode; const tNode = previousOrParentNode.tNode;
const isComponent = (directiveDef as ComponentDef<T>).template; const isComponent = (directiveDef as ComponentDef<T>).template;
@ -1494,7 +1496,7 @@ function generateInitialInputs(
export function createLContainer( export function createLContainer(
parentLNode: LNode, currentView: LView, template?: ComponentTemplate<any>, parentLNode: LNode, currentView: LView, template?: ComponentTemplate<any>,
isForViewContainerRef?: boolean): LContainer { isForViewContainerRef?: boolean): LContainer {
ngDevMode && assertNotNull(parentLNode, 'containers should have a parent'); ngDevMode && assertDefined(parentLNode, 'containers should have a parent');
return <LContainer>{ return <LContainer>{
views: [], views: [],
nextIndex: isForViewContainerRef ? null : 0, nextIndex: isForViewContainerRef ? null : 0,
@ -1611,7 +1613,7 @@ function refreshDynamicChildren() {
const lViewNode = container.views[i]; const lViewNode = container.views[i];
// The directives and pipes are not needed here as an existing view is only being refreshed. // The directives and pipes are not needed here as an existing view is only being refreshed.
const dynamicView = lViewNode.data; const dynamicView = lViewNode.data;
ngDevMode && assertNotNull(dynamicView.tView, 'TView must be allocated'); ngDevMode && assertDefined(dynamicView.tView, 'TView must be allocated');
renderEmbeddedTemplate(lViewNode, dynamicView.tView, dynamicView.context !, renderer); renderEmbeddedTemplate(lViewNode, dynamicView.tView, dynamicView.context !, renderer);
} }
} }
@ -1699,7 +1701,7 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags {
function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TView { function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TView {
ngDevMode && assertNodeType(parent, TNodeType.Container); ngDevMode && assertNodeType(parent, TNodeType.Container);
const containerTViews = (parent !.tNode as TContainerNode).tViews as TView[]; const containerTViews = (parent !.tNode as TContainerNode).tViews as TView[];
ngDevMode && assertNotNull(containerTViews, 'TView expected'); ngDevMode && assertDefined(containerTViews, 'TView expected');
ngDevMode && assertEqual(Array.isArray(containerTViews), true, 'TViews should be in an array'); ngDevMode && assertEqual(Array.isArray(containerTViews), true, 'TViews should be in an array');
if (viewIndex >= containerTViews.length || containerTViews[viewIndex] == null) { if (viewIndex >= containerTViews.length || containerTViews[viewIndex] == null) {
const tView = currentView.tView; const tView = currentView.tView;
@ -1773,7 +1775,7 @@ export function componentRefresh<T>(directiveIndex: number, elementIndex: number
ngDevMode && assertDataInRange(elementIndex); ngDevMode && assertDataInRange(elementIndex);
const element = data ![elementIndex] as LElementNode; const element = data ![elementIndex] as LElementNode;
ngDevMode && assertNodeType(element, TNodeType.Element); ngDevMode && assertNodeType(element, TNodeType.Element);
ngDevMode && assertNotNull(element.data, `Component's host node should have an LView attached.`); ngDevMode && assertDefined(element.data, `Component's host node should have an LView attached.`);
const hostView = element.data !; const hostView = element.data !;
// Only attached CheckAlways components or attached, dirty OnPush components should be checked // Only attached CheckAlways components or attached, dirty OnPush components should be checked
@ -1928,13 +1930,13 @@ export function projection(
function findComponentHost(lView: LView): LElementNode { function findComponentHost(lView: LView): LElementNode {
let viewRootLNode = lView.node; let viewRootLNode = lView.node;
while (viewRootLNode.tNode.type === TNodeType.View) { while (viewRootLNode.tNode.type === TNodeType.View) {
ngDevMode && assertNotNull(lView.parent, 'lView.parent'); ngDevMode && assertDefined(lView.parent, 'lView.parent');
lView = lView.parent !; lView = lView.parent !;
viewRootLNode = lView.node; viewRootLNode = lView.node;
} }
ngDevMode && assertNodeType(viewRootLNode, TNodeType.Element); ngDevMode && assertNodeType(viewRootLNode, TNodeType.Element);
ngDevMode && assertNotNull(viewRootLNode.data, 'node.data'); ngDevMode && assertDefined(viewRootLNode.data, 'node.data');
return viewRootLNode as LElementNode; return viewRootLNode as LElementNode;
} }
@ -2012,7 +2014,7 @@ export function markViewDirty(view: LView): void {
} }
currentView.flags |= LViewFlags.Dirty; currentView.flags |= LViewFlags.Dirty;
ngDevMode && assertNotNull(currentView !.context, 'rootContext'); ngDevMode && assertDefined(currentView !.context, 'rootContext');
scheduleTick(currentView !.context as RootContext); scheduleTick(currentView !.context as RootContext);
} }
@ -2033,7 +2035,7 @@ export function scheduleTick<T>(rootContext: RootContext) {
let res: null|((val: null) => void); let res: null|((val: null) => void);
rootContext.clean = new Promise<null>((r) => res = r); rootContext.clean = new Promise<null>((r) => res = r);
rootContext.scheduler(() => { rootContext.scheduler(() => {
tick(rootContext.component); tickRootContext(rootContext);
res !(null); res !(null);
rootContext.clean = _CLEAN_PROMISE; rootContext.clean = _CLEAN_PROMISE;
}); });
@ -2054,11 +2056,18 @@ export function scheduleTick<T>(rootContext: RootContext) {
*/ */
export function tick<T>(component: T): void { export function tick<T>(component: T): void {
const rootView = getRootView(component); const rootView = getRootView(component);
const rootComponent = (rootView.context as RootContext).component; const rootContext = rootView.context as RootContext;
tickRootContext(rootContext);
}
function tickRootContext(rootContext: RootContext) {
for (let i = 0; i < rootContext.components.length; i++) {
const rootComponent = rootContext.components[i];
const hostNode = _getComponentHostLElementNode(rootComponent); const hostNode = _getComponentHostLElementNode(rootComponent);
ngDevMode && assertNotNull(hostNode.data, 'Component host node should be attached to an LView'); ngDevMode && assertDefined(hostNode.data, 'Component host node should be attached to an LView');
renderComponentOrTemplate(hostNode, rootView, rootComponent); renderComponentOrTemplate(hostNode, getRootView(rootComponent), rootComponent);
}
} }
/** /**
@ -2069,7 +2078,7 @@ export function tick<T>(component: T): void {
*/ */
export function getRootView(component: any): LView { export function getRootView(component: any): LView {
ngDevMode && assertNotNull(component, 'component'); ngDevMode && assertDefined(component, 'component');
const lElementNode = _getComponentHostLElementNode(component); const lElementNode = _getComponentHostLElementNode(component);
let lView = lElementNode.view; let lView = lElementNode.view;
while (lView.parent) { while (lView.parent) {
@ -2093,7 +2102,7 @@ export function getRootView(component: any): LView {
*/ */
export function detectChanges<T>(component: T): void { export function detectChanges<T>(component: T): void {
const hostNode = _getComponentHostLElementNode(component); const hostNode = _getComponentHostLElementNode(component);
ngDevMode && assertNotNull(hostNode.data, 'Component host node should be attached to an LView'); ngDevMode && assertDefined(hostNode.data, 'Component host node should be attached to an LView');
detectChangesInternal(hostNode.data as LView, hostNode, component); detectChangesInternal(hostNode.data as LView, hostNode, component);
} }
@ -2142,7 +2151,7 @@ export function detectChangesInternal<T>(hostView: LView, hostNode: LElementNode
* @param component Component to mark as dirty. * @param component Component to mark as dirty.
*/ */
export function markDirty<T>(component: T) { export function markDirty<T>(component: T) {
ngDevMode && assertNotNull(component, 'component'); ngDevMode && assertDefined(component, 'component');
const lElementNode = _getComponentHostLElementNode(component); const lElementNode = _getComponentHostLElementNode(component);
markViewDirty(lElementNode.view); markViewDirty(lElementNode.view);
} }
@ -2388,7 +2397,7 @@ export function load<T>(index: number): T {
/** Retrieves a value from the `directives` array. */ /** Retrieves a value from the `directives` array. */
export function loadDirective<T>(index: number): T { export function loadDirective<T>(index: number): T {
ngDevMode && assertNotNull(directives, 'Directives array should be defined if reading a dir.'); ngDevMode && assertDefined(directives, 'Directives array should be defined if reading a dir.');
ngDevMode && assertDataInRange(index, directives !); ngDevMode && assertDataInRange(index, directives !);
return directives ![index]; return directives ![index];
} }
@ -2453,7 +2462,7 @@ export function assertPreviousIsParent() {
} }
function assertHasParent() { function assertHasParent() {
assertNotNull(getParentLNode(previousOrParentNode), 'previousOrParentNode should have a parent'); assertDefined(getParentLNode(previousOrParentNode), 'previousOrParentNode should have a parent');
} }
function assertDataInRange(index: number, arr?: any[]) { function assertDataInRange(index: number, arr?: any[]) {
@ -2484,9 +2493,9 @@ export function assertReservedSlotInitialized(slotOffset: number, numSlots: numb
} }
export function _getComponentHostLElementNode<T>(component: T): LElementNode { export function _getComponentHostLElementNode<T>(component: T): LElementNode {
ngDevMode && assertNotNull(component, 'expecting component got null'); ngDevMode && assertDefined(component, 'expecting component got null');
const lElementNode = (component as any)[NG_HOST_SYMBOL] as LElementNode; const lElementNode = (component as any)[NG_HOST_SYMBOL] as LElementNode;
ngDevMode && assertNotNull(component, 'object is not a component'); ngDevMode && assertDefined(component, 'object is not a component');
return lElementNode; return lElementNode;
} }

View File

@ -420,10 +420,10 @@ export interface RootContext {
clean: Promise<null>; clean: Promise<null>;
/** /**
* RootComponent - The component which was instantiated by the call to * RootComponents - The components that were instantiated by the call to
* {@link renderComponent}. * {@link renderComponent}.
*/ */
component: {}; components: {}[];
} }
/** /**

View File

@ -0,0 +1,73 @@
/**
* @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 {StaticProvider} from '../di/provider';
import {createInjector} from '../di/r3_injector';
import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '../linker/component_factory_resolver';
import {InternalNgModuleRef, NgModuleFactory as viewEngine_NgModuleFactory, NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory';
import {Type} from '../type';
import {stringify} from '../util';
import {assertDefined} from './assert';
import {ComponentFactoryResolver} from './component_ref';
export interface NgModuleType { ngModuleDef: NgModuleDef; }
export interface NgModuleDef { bootstrap: Type<any>[]; }
export const COMPONENT_FACTORY_RESOLVER: StaticProvider = {
provide: viewEngine_ComponentFactoryResolver,
useFactory: () => new ComponentFactoryResolver(),
deps: [],
};
export class NgModuleRef<T> extends viewEngine_NgModuleRef<T> implements InternalNgModuleRef<T> {
// tslint:disable-next-line:require-internal-with-underscore
_bootstrapComponents: Type<any>[] = [];
injector: Injector;
componentFactoryResolver: viewEngine_ComponentFactoryResolver;
instance: T;
destroyCbs: (() => void)[]|null = [];
constructor(ngModuleType: Type<T>, parentInjector: Injector|null) {
super();
const ngModuleDef = (ngModuleType as any as NgModuleType).ngModuleDef;
ngDevMode && assertDefined(
ngModuleDef,
`NgModule '${stringify(ngModuleType)}' is not a subtype of 'NgModuleType'.`);
this._bootstrapComponents = ngModuleDef.bootstrap;
const additionalProviders: StaticProvider[] = [
COMPONENT_FACTORY_RESOLVER, {
provide: viewEngine_NgModuleRef,
useValue: this,
}
];
this.injector = createInjector(ngModuleType, parentInjector, additionalProviders);
this.instance = this.injector.get(ngModuleType);
this.componentFactoryResolver = new ComponentFactoryResolver();
}
destroy(): void {
ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
this.destroyCbs !.forEach(fn => fn());
this.destroyCbs = null;
}
onDestroy(callback: () => void): void {
ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
this.destroyCbs !.push(callback);
}
}
export class NgModuleFactory<T> extends viewEngine_NgModuleFactory<T> {
constructor(public moduleType: Type<T>) { super(); }
create(parentInjector: Injector|null): viewEngine_NgModuleRef<T> {
return new NgModuleRef(this.moduleType, parentInjector);
}
}

View File

@ -6,16 +6,16 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {assertEqual, assertNotNull} from './assert'; import {assertDefined, assertEqual} from './assert';
import {LNode, TNodeType} from './interfaces/node'; import {LNode, TNodeType} from './interfaces/node';
export function assertNodeType(node: LNode, type: TNodeType) { export function assertNodeType(node: LNode, type: TNodeType) {
assertNotNull(node, 'should be called with a node'); assertDefined(node, 'should be called with a node');
assertEqual(node.tNode.type, type, `should be a ${typeName(type)}`); assertEqual(node.tNode.type, type, `should be a ${typeName(type)}`);
} }
export function assertNodeOfPossibleTypes(node: LNode, ...types: TNodeType[]) { export function assertNodeOfPossibleTypes(node: LNode, ...types: TNodeType[]) {
assertNotNull(node, 'should be called with a node'); assertDefined(node, 'should be called with a node');
const found = types.some(type => node.tNode.type === type); const found = types.some(type => node.tNode.type === type);
assertEqual(found, true, `Should be one of ${types.map(typeName).join(', ')}`); assertEqual(found, true, `Should be one of ${types.map(typeName).join(', ')}`);
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {assertNotNull} from './assert'; import {assertDefined} from './assert';
import {callHooks} from './hooks'; import {callHooks} from './hooks';
import {LContainer, unusedValueExportToPlacateAjd as unused1} from './interfaces/container'; import {LContainer, unusedValueExportToPlacateAjd as unused1} from './interfaces/container';
import {LContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, TNodeFlags, TNodeType, unusedValueExportToPlacateAjd as unused2} from './interfaces/node'; import {LContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, TNodeFlags, TNodeType, unusedValueExportToPlacateAjd as unused2} from './interfaces/node';

View File

@ -8,7 +8,7 @@
import './ng_dev_mode'; import './ng_dev_mode';
import {assertNotNull} from './assert'; import {assertDefined} from './assert';
import {AttributeMarker, TAttributes, TNode, unusedValueExportToPlacateAjd as unused1} from './interfaces/node'; import {AttributeMarker, TAttributes, TNode, unusedValueExportToPlacateAjd as unused1} from './interfaces/node';
import {CssSelector, CssSelectorList, NG_PROJECT_AS_ATTR_NAME, SelectorFlags, unusedValueExportToPlacateAjd as unused2} from './interfaces/projection'; import {CssSelector, CssSelectorList, NG_PROJECT_AS_ATTR_NAME, SelectorFlags, unusedValueExportToPlacateAjd as unused2} from './interfaces/projection';
@ -36,7 +36,7 @@ function isCssClassMatching(nodeClassAttrVal: string, cssClassToMatch: string):
* @returns true if node matches the selector. * @returns true if node matches the selector.
*/ */
export function isNodeMatchingSelector(tNode: TNode, selector: CssSelector): boolean { export function isNodeMatchingSelector(tNode: TNode, selector: CssSelector): boolean {
ngDevMode && assertNotNull(selector[0], 'Selector should have a tag name'); ngDevMode && assertDefined(selector[0], 'Selector should have a tag name');
let mode: SelectorFlags = SelectorFlags.ELEMENT; let mode: SelectorFlags = SelectorFlags.ELEMENT;
const nodeAttrs = tNode.attrs !; const nodeAttrs = tNode.attrs !;

View File

@ -15,7 +15,7 @@ import {QueryList as viewEngine_QueryList} from '../linker/query_list';
import {Type} from '../type'; import {Type} from '../type';
import {getSymbolIterator} from '../util'; import {getSymbolIterator} from '../util';
import {assertEqual, assertNotNull} from './assert'; import {assertDefined, assertEqual} from './assert';
import {ReadFromInjectorFn, getOrCreateNodeInjectorForNode} from './di'; import {ReadFromInjectorFn, getOrCreateNodeInjectorForNode} from './di';
import {assertPreviousIsParent, getCurrentQueries, store, storeCleanupWithContext} from './instructions'; import {assertPreviousIsParent, getCurrentQueries, store, storeCleanupWithContext} from './instructions';
import {DirectiveDef, unusedValueExportToPlacateAjd as unused1} from './interfaces/definition'; import {DirectiveDef, unusedValueExportToPlacateAjd as unused1} from './interfaces/definition';
@ -163,7 +163,7 @@ export class LQueries_ implements LQueries {
let query = this.deep; let query = this.deep;
while (query) { while (query) {
ngDevMode && ngDevMode &&
assertNotNull( assertDefined(
query.containerValues, 'View queries need to have a pointer to container values.'); query.containerValues, 'View queries need to have a pointer to container values.');
query.containerValues !.splice(index, 0, query.values); query.containerValues !.splice(index, 0, query.values);
query = query.next; query = query.next;
@ -179,7 +179,7 @@ export class LQueries_ implements LQueries {
let query = this.deep; let query = this.deep;
while (query) { while (query) {
ngDevMode && ngDevMode &&
assertNotNull( assertDefined(
query.containerValues, 'View queries need to have a pointer to container values.'); query.containerValues, 'View queries need to have a pointer to container values.');
const removed = query.containerValues !.splice(index, 1); const removed = query.containerValues !.splice(index, 1);
@ -273,7 +273,7 @@ function add(query: LQuery<any>| null, node: LNode) {
if (directiveIdx !== null) { if (directiveIdx !== null) {
// a node is matching a predicate - determine what to read // a node is matching a predicate - determine what to read
// note that queries using name selector must specify read strategy // note that queries using name selector must specify read strategy
ngDevMode && assertNotNull(predicate.read, 'the node should have a predicate'); ngDevMode && assertDefined(predicate.read, 'the node should have a predicate');
const result = readFromNodeInjector(nodeInjector, node, predicate.read !, directiveIdx); const result = readFromNodeInjector(nodeInjector, node, predicate.read !, directiveIdx);
if (result !== null) { if (result !== null) {
addMatch(query, result); addMatch(query, result);

View File

@ -6,8 +6,10 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ApplicationRef} from '../application_ref';
import {ChangeDetectorRef as viewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref';
import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_container_ref'; import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_container_ref';
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef} from '../linker/view_ref'; import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEngine_InternalViewRef} from '../linker/view_ref';
import {checkNoChanges, detectChanges, markViewDirty, storeCleanupFn} from './instructions'; import {checkNoChanges, detectChanges, markViewDirty, storeCleanupFn} from './instructions';
import {ComponentTemplate} from './interfaces/definition'; import {ComponentTemplate} from './interfaces/definition';
@ -15,7 +17,15 @@ import {LViewNode} from './interfaces/node';
import {LView, LViewFlags} from './interfaces/view'; import {LView, LViewFlags} from './interfaces/view';
import {destroyLView} from './node_manipulation'; import {destroyLView} from './node_manipulation';
export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T> { // Needed due to tsickle downleveling where multiple `implements` with classes creates
// multiple @extends in Closure annotations, which is illegal. This workaround fixes
// the multiple @extends by making the annotation @implements instead
export interface viewEngine_ChangeDetectorRef_interface extends viewEngine_ChangeDetectorRef {}
export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_InternalViewRef,
viewEngine_ChangeDetectorRef_interface {
private _appRef: ApplicationRef|null;
context: T; context: T;
rootNodes: any[]; rootNodes: any[];
@ -210,6 +220,10 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T> {
* introduce other changes. * introduce other changes.
*/ */
checkNoChanges(): void { checkNoChanges(this.context); } checkNoChanges(): void { checkNoChanges(this.context); }
detachFromAppRef() { this._appRef = null; }
attachToAppRef(appRef: ApplicationRef) { this._appRef = appRef; }
} }

View File

@ -0,0 +1,95 @@
/**
* @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 {ApplicationModule, ApplicationRef, DoCheck, InjectFlags, InjectorType, Input, OnInit, PlatformRef, TestabilityRegistry, Type, defineInjector, inject, ɵE as elementStart, ɵNgModuleDef as NgModuleDef, ɵRenderFlags as RenderFlags, ɵT as text, ɵdefineComponent as defineComponent, ɵe as elementEnd, ɵi1 as interpolation1, ɵt as textBinding} from '@angular/core';
import {getTestBed, withBody} from '@angular/core/testing';
import {BrowserModule, EVENT_MANAGER_PLUGINS, platformBrowser} from '@angular/platform-browser';
import {BROWSER_MODULE_PROVIDERS} from '../../platform-browser/src/browser';
import {APPLICATION_MODULE_PROVIDERS} from '../src/application_module';
import {NgModuleFactory} from '../src/render3/ng_module_ref';
describe('ApplicationRef bootstrap', () => {
class HelloWorldComponent implements OnInit, DoCheck {
log: string[] = [];
name = 'World';
static ngComponentDef = defineComponent({
type: HelloWorldComponent,
selectors: [['hello-world']],
factory: () => new HelloWorldComponent(),
template: function(rf: RenderFlags, ctx: HelloWorldComponent): void {
if (rf & RenderFlags.Create) {
elementStart(0, 'div');
text(1);
elementEnd();
}
if (rf & RenderFlags.Update) {
textBinding(1, interpolation1('Hello ', ctx.name, ''));
}
}
});
ngOnInit(): void { this.log.push('OnInit'); }
ngDoCheck(): void { this.log.push('DoCheck'); }
}
class MyAppModule {
static ngInjectorDef =
defineInjector({factory: () => new MyAppModule(), imports: [BrowserModule]});
static ngModuleDef = defineNgModule({bootstrap: [HelloWorldComponent]});
}
it('should bootstrap hello world', withBody('<hello-world></hello-world>', async() => {
const MyAppModuleFactory = new NgModuleFactory(MyAppModule);
const moduleRef =
await getTestBed().platform.bootstrapModuleFactory(MyAppModuleFactory, {ngZone: 'noop'});
const appRef = moduleRef.injector.get(ApplicationRef);
const helloWorldComponent = appRef.components[0].instance as HelloWorldComponent;
expect(document.body.innerHTML).toEqual('<hello-world><div>Hello World</div></hello-world>');
// TODO(jasonaden): Get with Kara on lifecycle hooks
// expect(helloWorldComponent.log).toEqual(['OnInit', 'DoCheck']);
helloWorldComponent.name = 'Mundo';
appRef.tick();
expect(document.body.innerHTML).toEqual('<hello-world><div>Hello Mundo</div></hello-world>');
// TODO(jasonaden): Get with Kara on lifecycle hooks
// expect(helloWorldComponent.log).toEqual(['OnInit', 'DoCheck', 'DoCheck']);
// Cleanup TestabilityRegistry
const registry: TestabilityRegistry = getTestBed().get(TestabilityRegistry);
registry.unregisterAllApplications();
}));
});
/////////////////////////////////////////////////////////
// These go away when Compiler is ready
(BrowserModule as any as InjectorType<BrowserModule>).ngInjectorDef = defineInjector({
factory: function BrowserModule_Factory() {
return new BrowserModule(inject(BrowserModule, InjectFlags.Optional | InjectFlags.SkipSelf));
},
imports: [ApplicationModule],
providers: BROWSER_MODULE_PROVIDERS
});
(ApplicationModule as any as InjectorType<ApplicationModule>).ngInjectorDef = defineInjector({
factory: function ApplicationModule_Factory() {
return new ApplicationModule(inject(ApplicationRef));
},
providers: APPLICATION_MODULE_PROVIDERS
});
export function defineNgModule({bootstrap}: {bootstrap?: Type<any>[]}): NgModuleDef {
return {
bootstrap: bootstrap || [],
};
}
/////////////////////////////////////////////////////////

View File

@ -56,6 +56,9 @@
{ {
"name": "createLView" "name": "createLView"
}, },
{
"name": "createRootContext"
},
{ {
"name": "createTNode" "name": "createTNode"
}, },

View File

@ -2418,7 +2418,7 @@
"name": "assertInterpolationSymbols" "name": "assertInterpolationSymbols"
}, },
{ {
"name": "assertNotNull$1" "name": "assertNotNull"
}, },
{ {
"name": "assertPlatform" "name": "assertPlatform"

View File

@ -266,6 +266,9 @@
{ {
"name": "createOutput" "name": "createOutput"
}, },
{
"name": "createRootContext"
},
{ {
"name": "createTNode" "name": "createTNode"
}, },
@ -657,7 +660,7 @@
"name": "throwMultipleComponentError" "name": "throwMultipleComponentError"
}, },
{ {
"name": "tick" "name": "tickRootContext"
}, },
{ {
"name": "trackByIdentity" "name": "trackByIdentity"

View File

@ -41,6 +41,8 @@ describe('InjectorDef-based createInjector()', () => {
const STATIC_TOKEN = new InjectionToken<StaticService>('STATIC_TOKEN'); const STATIC_TOKEN = new InjectionToken<StaticService>('STATIC_TOKEN');
const LOCALE = new InjectionToken<string[]>('LOCALE');
class ServiceWithDep { class ServiceWithDep {
constructor(readonly service: Service) {} constructor(readonly service: Service) {}
@ -50,6 +52,15 @@ describe('InjectorDef-based createInjector()', () => {
}); });
} }
class ServiceWithMultiDep {
constructor(readonly locale: string[]) {}
static ngInjectableDef = defineInjectable({
providedIn: null,
factory: () => new ServiceWithMultiDep(inject(LOCALE)),
});
}
class ServiceTwo { class ServiceTwo {
static ngInjectableDef = defineInjectable({ static ngInjectableDef = defineInjectable({
providedIn: null, providedIn: null,
@ -112,6 +123,9 @@ describe('InjectorDef-based createInjector()', () => {
imports: [IntermediateModule], imports: [IntermediateModule],
providers: [ providers: [
ServiceWithDep, ServiceWithDep,
ServiceWithMultiDep,
{provide: LOCALE, multi: true, useValue: 'en'},
{provide: LOCALE, multi: true, useValue: 'es'},
Service, Service,
{provide: SERVICE_TOKEN, useExisting: Service}, {provide: SERVICE_TOKEN, useExisting: Service},
CircularA, CircularA,
@ -168,6 +182,12 @@ describe('InjectorDef-based createInjector()', () => {
expect(instance.service).toBe(injector.get(Service)); expect(instance.service).toBe(injector.get(Service));
}); });
it('injects a service with dependencies on multi-providers', () => {
const instance = injector.get(ServiceWithMultiDep);
expect(instance instanceof ServiceWithMultiDep);
expect(instance.locale).toEqual(['en', 'es']);
});
it('injects a token with useExisting', () => { it('injects a token with useExisting', () => {
const instance = injector.get(SERVICE_TOKEN); const instance = injector.get(SERVICE_TOKEN);
expect(instance).toBe(injector.get(Service)); expect(instance).toBe(injector.get(Service));

View File

@ -7,9 +7,9 @@
*/ */
import {ComponentFactory, DoCheck, ViewEncapsulation, createInjector, defineInjectable, defineInjector} from '../../src/core'; import {DoCheck, ViewEncapsulation, createInjector, defineInjectable, defineInjector} from '../../src/core';
import {getRenderedText} from '../../src/render3/component'; import {getRenderedText} from '../../src/render3/component';
import {LifecycleHooksFeature, defineComponent, directiveInject, markDirty} from '../../src/render3/index'; import {ComponentFactory, LifecycleHooksFeature, defineComponent, directiveInject, markDirty} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, text, textBinding, tick} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, text, textBinding, tick} from '../../src/render3/instructions';
import {ComponentDef, DirectiveDef, RenderFlags} from '../../src/render3/interfaces/definition'; import {ComponentDef, DirectiveDef, RenderFlags} from '../../src/render3/interfaces/definition';
import {createRendererType2} from '../../src/view/index'; import {createRendererType2} from '../../src/view/index';
@ -364,4 +364,27 @@ describe('recursive components', () => {
tick(comp); tick(comp);
expect(events).toEqual(['check6', 'check2', 'check0', 'check1', 'check5', 'check3', 'check4']); expect(events).toEqual(['check6', 'check2', 'check0', 'check1', 'check5', 'check3', 'check4']);
}); });
it('should map inputs minified & unminified names', async() => {
class TestInputsComponent {
minifiedName: string;
static ngComponentDef = defineComponent({
type: TestInputsComponent,
selectors: [['test-inputs']],
inputs: {minifiedName: 'unminifiedName'},
factory: () => new TestInputsComponent(),
template: function(rf: RenderFlags, ctx: TestInputsComponent): void {
// Template not needed for this test
}
});
}
const testInputsComponentFactory = new ComponentFactory(TestInputsComponent.ngComponentDef);
expect([
{propName: 'minifiedName', templateName: 'unminifiedName'}
]).toEqual(testInputsComponentFactory.inputs);
});
}); });

View File

@ -135,7 +135,7 @@ export class ComponentFixture<T> extends BaseFixture {
// Fixtures above are preferred way of testing Components and Templates // Fixtures above are preferred way of testing Components and Templates
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
export const document = ((global || window) as any).document; export const document = ((typeof global == 'object' && global || window) as any).document;
export let containerEl: HTMLElement = null !; export let containerEl: HTMLElement = null !;
let host: LElementNode|null; let host: LElementNode|null;
const isRenderer2 = const isRenderer2 =

View File

@ -7,7 +7,7 @@
*/ */
import {CommonModule, PlatformLocation, ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID} from '@angular/common'; import {CommonModule, PlatformLocation, ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID} from '@angular/common';
import {APP_ID, ApplicationModule, ErrorHandler, ModuleWithProviders, NgModule, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, PlatformRef, RendererFactory2, RootRenderer, Sanitizer, SkipSelf, StaticProvider, Testability, createPlatformFactory, platformCore, ɵAPP_ROOT as APP_ROOT} from '@angular/core'; import {APP_ID, ApplicationModule, ClassProvider, ConstructorSansProvider, ErrorHandler, ExistingProvider, FactoryProvider, Inject, InjectionToken, ModuleWithProviders, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, PlatformRef, RendererFactory2, RootRenderer, Sanitizer, SkipSelf, StaticProvider, Testability, TypeProvider, ValueProvider, createPlatformFactory, platformCore, ɵAPP_ROOT as APP_ROOT} from '@angular/core';
import {BrowserDomAdapter} from './browser/browser_adapter'; import {BrowserDomAdapter} from './browser/browser_adapter';
import {BrowserPlatformLocation} from './browser/location/browser_platform_location'; import {BrowserPlatformLocation} from './browser/location/browser_platform_location';
@ -20,7 +20,7 @@ import {getDOM} from './dom/dom_adapter';
import {DomRendererFactory2} from './dom/dom_renderer'; import {DomRendererFactory2} from './dom/dom_renderer';
import {DOCUMENT} from './dom/dom_tokens'; import {DOCUMENT} from './dom/dom_tokens';
import {DomEventsPlugin} from './dom/events/dom_events'; import {DomEventsPlugin} from './dom/events/dom_events';
import {EVENT_MANAGER_PLUGINS, EventManager} from './dom/events/event_manager'; import {EVENT_MANAGER_PLUGINS, EventManager, EventManagerPlugin} from './dom/events/event_manager';
import {HAMMER_GESTURE_CONFIG, HammerGestureConfig, HammerGesturesPlugin} from './dom/events/hammer_gestures'; import {HAMMER_GESTURE_CONFIG, HammerGestureConfig, HammerGesturesPlugin} from './dom/events/hammer_gestures';
import {KeyEventsPlugin} from './dom/events/key_events'; import {KeyEventsPlugin} from './dom/events/key_events';
import {DomSharedStylesHost, SharedStylesHost} from './dom/shared_styles_host'; import {DomSharedStylesHost, SharedStylesHost} from './dom/shared_styles_host';
@ -60,34 +60,47 @@ export function _document(): any {
return document; return document;
} }
export const BROWSER_MODULE_PROVIDERS: StaticProvider[] = [
BROWSER_SANITIZATION_PROVIDERS,
{provide: APP_ROOT, useValue: true},
{provide: ErrorHandler, useFactory: errorHandler, deps: []},
{
provide: EVENT_MANAGER_PLUGINS,
useClass: DomEventsPlugin,
multi: true,
deps: [DOCUMENT, NgZone, PLATFORM_ID]
},
{provide: EVENT_MANAGER_PLUGINS, useClass: KeyEventsPlugin, multi: true, deps: [DOCUMENT]},
{
provide: EVENT_MANAGER_PLUGINS,
useClass: HammerGesturesPlugin,
multi: true,
deps: [DOCUMENT, HAMMER_GESTURE_CONFIG]
},
{provide: HAMMER_GESTURE_CONFIG, useClass: HammerGestureConfig, deps: []},
{
provide: DomRendererFactory2,
useClass: DomRendererFactory2,
deps: [EventManager, DomSharedStylesHost]
},
{provide: RendererFactory2, useExisting: DomRendererFactory2},
{provide: SharedStylesHost, useExisting: DomSharedStylesHost},
{provide: DomSharedStylesHost, useClass: DomSharedStylesHost, deps: [DOCUMENT]},
{provide: Testability, useClass: Testability, deps: [NgZone]},
{provide: EventManager, useClass: EventManager, deps: [EVENT_MANAGER_PLUGINS, NgZone]},
ELEMENT_PROBE_PROVIDERS,
{provide: Meta, useClass: Meta, deps: [DOCUMENT]},
{provide: Title, useClass: Title, deps: [DOCUMENT]},
];
/** /**
* The ng module for the browser. * The ng module for the browser.
* *
* *
*/ */
@NgModule({ @NgModule({providers: BROWSER_MODULE_PROVIDERS, exports: [CommonModule, ApplicationModule]})
providers: [
BROWSER_SANITIZATION_PROVIDERS,
{provide: APP_ROOT, useValue: true},
{provide: ErrorHandler, useFactory: errorHandler, deps: []},
{provide: EVENT_MANAGER_PLUGINS, useClass: DomEventsPlugin, multi: true},
{provide: EVENT_MANAGER_PLUGINS, useClass: KeyEventsPlugin, multi: true},
{provide: EVENT_MANAGER_PLUGINS, useClass: HammerGesturesPlugin, multi: true},
{provide: HAMMER_GESTURE_CONFIG, useClass: HammerGestureConfig},
DomRendererFactory2,
{provide: RendererFactory2, useExisting: DomRendererFactory2},
{provide: SharedStylesHost, useExisting: DomSharedStylesHost},
DomSharedStylesHost,
Testability,
EventManager,
ELEMENT_PROBE_PROVIDERS,
Meta,
Title,
],
exports: [CommonModule, ApplicationModule]
})
export class BrowserModule { export class BrowserModule {
constructor(@Optional() @SkipSelf() parentModule: BrowserModule) { constructor(@Optional() @SkipSelf() @Inject(BrowserModule) parentModule: BrowserModule|null) {
if (parentModule) { if (parentModule) {
throw new Error( throw new Error(
`BrowserModule has already been loaded. If you need access to common directives such as NgIf and NgFor from a lazy loaded module, import CommonModule instead.`); `BrowserModule has already been loaded. If you need access to common directives such as NgIf and NgFor from a lazy loaded module, import CommonModule instead.`);

View File

@ -143,6 +143,11 @@ export declare abstract class ComponentRef<C> {
abstract onDestroy(callback: Function): void; abstract onDestroy(callback: Function): void;
} }
/** @experimental */
export interface ConstructorSansProvider {
deps?: any[];
}
export declare const ContentChild: ContentChildDecorator; export declare const ContentChild: ContentChildDecorator;
export interface ContentChildDecorator { export interface ContentChildDecorator {
@ -168,7 +173,7 @@ export interface ContentChildrenDecorator {
} }
/** @experimental */ /** @experimental */
export declare function createInjector(defType: any, parent?: Injector | null): Injector; export declare function createInjector(defType: any, parent?: Injector | null, additionalProviders?: StaticProvider[] | null): Injector;
/** @experimental */ /** @experimental */
export declare function createPlatform(injector: Injector): PlatformRef; export declare function createPlatform(injector: Injector): PlatformRef;
@ -609,7 +614,7 @@ export interface Predicate<T> {
(value: T): boolean; (value: T): boolean;
} }
export declare type Provider = TypeProvider | ValueProvider | ClassProvider | ExistingProvider | FactoryProvider | any[]; export declare type Provider = TypeProvider | ValueProvider | ClassProvider | ConstructorProvider | ExistingProvider | FactoryProvider | any[];
export declare abstract class Query { export declare abstract class Query {
} }

View File

@ -1,5 +1,5 @@
export declare class BrowserModule { export declare class BrowserModule {
constructor(parentModule: BrowserModule); constructor(parentModule: BrowserModule | null);
/** @experimental */ static withServerTransition(params: { /** @experimental */ static withServerTransition(params: {
appId: string; appId: string;
}): ModuleWithProviders; }): ModuleWithProviders;