feat(bootstrap): add platform and app initializers
Often some init logic needs to run when a platform or an application is boostrapped. For example, boostraping a platform requires initializing the dom adapter. Now, it can be done as follows: new Provider(PLATFORM_INITIALIZER, {useValue: initDomAdapter, multi: true}), All platform initializers will be run after the platform injector has been created. Similarly, all application initializers will be run after the app injector has been created. Closes #5355
This commit is contained in:
parent
3fa287aae2
commit
3c43a8c549
@ -9,6 +9,7 @@ export 'package:angular2/src/common/pipes.dart';
|
|||||||
export 'package:angular2/src/facade/facade.dart';
|
export 'package:angular2/src/facade/facade.dart';
|
||||||
export 'package:angular2/src/core/application_ref.dart'
|
export 'package:angular2/src/core/application_ref.dart'
|
||||||
hide ApplicationRef_, PlatformRef_;
|
hide ApplicationRef_, PlatformRef_;
|
||||||
|
export 'package:angular2/src/core/application_tokens.dart' show APP_ID, APP_COMPONENT, APP_INITIALIZER, PLATFORM_INITIALIZER;
|
||||||
export 'package:angular2/src/core/linker.dart';
|
export 'package:angular2/src/core/linker.dart';
|
||||||
export 'package:angular2/src/core/zone.dart';
|
export 'package:angular2/src/core/zone.dart';
|
||||||
export 'package:angular2/src/core/render.dart';
|
export 'package:angular2/src/core/render.dart';
|
||||||
|
@ -10,7 +10,12 @@ export * from './src/common/pipes';
|
|||||||
export * from './src/facade/facade';
|
export * from './src/facade/facade';
|
||||||
export * from './src/core/linker';
|
export * from './src/core/linker';
|
||||||
export {platform, createNgZone, PlatformRef, ApplicationRef} from './src/core/application_ref';
|
export {platform, createNgZone, PlatformRef, ApplicationRef} from './src/core/application_ref';
|
||||||
export {APP_ID, APP_COMPONENT} from './src/core/application_tokens';
|
export {
|
||||||
|
APP_ID,
|
||||||
|
APP_COMPONENT,
|
||||||
|
APP_INITIALIZER,
|
||||||
|
PLATFORM_INITIALIZER
|
||||||
|
} from './src/core/application_tokens';
|
||||||
export * from './src/core/zone';
|
export * from './src/core/zone';
|
||||||
export * from './src/core/render';
|
export * from './src/core/render';
|
||||||
export * from './src/common/directives';
|
export * from './src/common/directives';
|
||||||
|
@ -13,8 +13,7 @@ import {Type, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
|
|||||||
import {Promise} from 'angular2/src/facade/promise';
|
import {Promise} from 'angular2/src/facade/promise';
|
||||||
import {
|
import {
|
||||||
BROWSER_PROVIDERS,
|
BROWSER_PROVIDERS,
|
||||||
BROWSER_APP_COMMON_PROVIDERS,
|
BROWSER_APP_COMMON_PROVIDERS
|
||||||
initDomAdapter
|
|
||||||
} from 'angular2/src/platform/browser_common';
|
} from 'angular2/src/platform/browser_common';
|
||||||
import {COMPILER_PROVIDERS} from 'angular2/compiler';
|
import {COMPILER_PROVIDERS} from 'angular2/compiler';
|
||||||
import {ComponentRef, platform, reflector} from 'angular2/core';
|
import {ComponentRef, platform, reflector} from 'angular2/core';
|
||||||
@ -120,8 +119,6 @@ export function bootstrap(
|
|||||||
appComponentType: Type,
|
appComponentType: Type,
|
||||||
customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ComponentRef> {
|
customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ComponentRef> {
|
||||||
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||||
initDomAdapter();
|
|
||||||
|
|
||||||
let appProviders =
|
let appProviders =
|
||||||
isPresent(customProviders) ? [BROWSER_APP_PROVIDERS, customProviders] : BROWSER_APP_PROVIDERS;
|
isPresent(customProviders) ? [BROWSER_APP_PROVIDERS, customProviders] : BROWSER_APP_PROVIDERS;
|
||||||
return platform(BROWSER_PROVIDERS).application(appProviders).bootstrap(appComponentType);
|
return platform(BROWSER_PROVIDERS).application(appProviders).bootstrap(appComponentType);
|
||||||
|
@ -12,8 +12,7 @@ import {Type, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
|
|||||||
import {Promise} from 'angular2/src/facade/promise';
|
import {Promise} from 'angular2/src/facade/promise';
|
||||||
import {
|
import {
|
||||||
BROWSER_PROVIDERS,
|
BROWSER_PROVIDERS,
|
||||||
BROWSER_APP_COMMON_PROVIDERS,
|
BROWSER_APP_COMMON_PROVIDERS
|
||||||
initDomAdapter
|
|
||||||
} from 'angular2/src/platform/browser_common';
|
} from 'angular2/src/platform/browser_common';
|
||||||
import {ComponentRef, platform, reflector} from 'angular2/core';
|
import {ComponentRef, platform, reflector} from 'angular2/core';
|
||||||
|
|
||||||
@ -31,7 +30,6 @@ export const BROWSER_APP_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
|||||||
export function bootstrapStatic(appComponentType: Type,
|
export function bootstrapStatic(appComponentType: Type,
|
||||||
customProviders?: Array<any /*Type | Provider | any[]*/>,
|
customProviders?: Array<any /*Type | Provider | any[]*/>,
|
||||||
initReflector?: Function): Promise<ComponentRef> {
|
initReflector?: Function): Promise<ComponentRef> {
|
||||||
initDomAdapter();
|
|
||||||
if (isPresent(initReflector)) {
|
if (isPresent(initReflector)) {
|
||||||
initReflector();
|
initReflector();
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,9 @@ import {provide, Provider, Injector, OpaqueToken} from 'angular2/src/core/di';
|
|||||||
import {
|
import {
|
||||||
APP_COMPONENT_REF_PROMISE,
|
APP_COMPONENT_REF_PROMISE,
|
||||||
APP_COMPONENT,
|
APP_COMPONENT,
|
||||||
APP_ID_RANDOM_PROVIDER
|
APP_ID_RANDOM_PROVIDER,
|
||||||
|
PLATFORM_INITIALIZER,
|
||||||
|
APP_INITIALIZER
|
||||||
} from './application_tokens';
|
} from './application_tokens';
|
||||||
import {
|
import {
|
||||||
Promise,
|
Promise,
|
||||||
@ -30,7 +32,6 @@ import {wtfLeave, wtfCreateScope, WtfScopeFn} from './profile/profile';
|
|||||||
import {ChangeDetectorRef} from 'angular2/src/core/change_detection/change_detector_ref';
|
import {ChangeDetectorRef} from 'angular2/src/core/change_detection/change_detector_ref';
|
||||||
import {lockDevMode} from 'angular2/src/facade/lang';
|
import {lockDevMode} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct providers specific to an individual root component.
|
* Construct providers specific to an individual root component.
|
||||||
*/
|
*/
|
||||||
@ -103,15 +104,32 @@ export function platform(providers?: Array<Type | Provider | any[]>): PlatformRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispose the existing platform.
|
||||||
|
*/
|
||||||
|
export function disposePlatform(): void {
|
||||||
|
if (isPresent(_platform)) {
|
||||||
|
_platform.dispose();
|
||||||
|
_platform = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function _createPlatform(providers?: Array<Type | Provider | any[]>): PlatformRef {
|
function _createPlatform(providers?: Array<Type | Provider | any[]>): PlatformRef {
|
||||||
_platformProviders = providers;
|
_platformProviders = providers;
|
||||||
_platform = new PlatformRef_(Injector.resolveAndCreate(providers), () => {
|
let injector = Injector.resolveAndCreate(providers);
|
||||||
|
_platform = new PlatformRef_(injector, () => {
|
||||||
_platform = null;
|
_platform = null;
|
||||||
_platformProviders = null;
|
_platformProviders = null;
|
||||||
});
|
});
|
||||||
|
_runPlatformInitializers(injector);
|
||||||
return _platform;
|
return _platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _runPlatformInitializers(injector: Injector): void {
|
||||||
|
let inits: Function[] = injector.getOptional(PLATFORM_INITIALIZER);
|
||||||
|
if (isPresent(inits)) inits.forEach(init => init());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Angular platform is the entry point for Angular on a web page. Each page
|
* The Angular platform is the entry point for Angular on a web page. Each page
|
||||||
* has exactly one platform, and services (such as reflection) which are common
|
* has exactly one platform, and services (such as reflection) which are common
|
||||||
@ -236,11 +254,12 @@ export class PlatformRef_ extends PlatformRef {
|
|||||||
});
|
});
|
||||||
app = new ApplicationRef_(this, zone, injector);
|
app = new ApplicationRef_(this, zone, injector);
|
||||||
this._applications.push(app);
|
this._applications.push(app);
|
||||||
|
_runAppInitializers(injector);
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
this._applications.forEach((app) => app.dispose());
|
ListWrapper.clone(this._applications).forEach((app) => app.dispose());
|
||||||
this._disposeListeners.forEach((dispose) => dispose());
|
this._disposeListeners.forEach((dispose) => dispose());
|
||||||
this._dispose();
|
this._dispose();
|
||||||
}
|
}
|
||||||
@ -249,6 +268,11 @@ export class PlatformRef_ extends PlatformRef {
|
|||||||
_applicationDisposed(app: ApplicationRef): void { ListWrapper.remove(this._applications, app); }
|
_applicationDisposed(app: ApplicationRef): void { ListWrapper.remove(this._applications, app); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _runAppInitializers(injector: Injector): void {
|
||||||
|
let inits: Function[] = injector.getOptional(APP_INITIALIZER);
|
||||||
|
if (isPresent(inits)) inits.forEach(init => init());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reference to an Angular application running on a page.
|
* A reference to an Angular application running on a page.
|
||||||
*
|
*
|
||||||
@ -439,7 +463,7 @@ export class ApplicationRef_ extends ApplicationRef {
|
|||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
// TODO(alxhub): Dispose of the NgZone.
|
// TODO(alxhub): Dispose of the NgZone.
|
||||||
this._rootComponents.forEach((ref) => ref.dispose());
|
ListWrapper.clone(this._rootComponents).forEach((ref) => ref.dispose());
|
||||||
this._disposeListeners.forEach((dispose) => dispose());
|
this._disposeListeners.forEach((dispose) => dispose());
|
||||||
this._platform._applicationDisposed(this);
|
this._platform._applicationDisposed(this);
|
||||||
}
|
}
|
||||||
|
@ -48,3 +48,14 @@ export const APP_ID_RANDOM_PROVIDER: Provider =
|
|||||||
function _randomChar(): string {
|
function _randomChar(): string {
|
||||||
return StringWrapper.fromCharCode(97 + Math.floor(Math.random() * 25));
|
return StringWrapper.fromCharCode(97 + Math.floor(Math.random() * 25));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function that will be executed when a platform is initialized.
|
||||||
|
*/
|
||||||
|
export const PLATFORM_INITIALIZER: OpaqueToken =
|
||||||
|
CONST_EXPR(new OpaqueToken("Platform Initializer"));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function that will be executed when an application is initialized.
|
||||||
|
*/
|
||||||
|
export const APP_INITIALIZER: OpaqueToken = CONST_EXPR(new OpaqueToken("Application Initializer"));
|
@ -11,13 +11,13 @@ import {
|
|||||||
reflector,
|
reflector,
|
||||||
APPLICATION_COMMON_PROVIDERS,
|
APPLICATION_COMMON_PROVIDERS,
|
||||||
PLATFORM_COMMON_PROVIDERS,
|
PLATFORM_COMMON_PROVIDERS,
|
||||||
EVENT_MANAGER_PLUGINS
|
EVENT_MANAGER_PLUGINS,
|
||||||
|
PLATFORM_INITIALIZER
|
||||||
} from "angular2/core";
|
} from "angular2/core";
|
||||||
import {COMMON_DIRECTIVES, COMMON_PIPES, FORM_PROVIDERS} from "angular2/common";
|
import {COMMON_DIRECTIVES, COMMON_PIPES, FORM_PROVIDERS} from "angular2/common";
|
||||||
import {Renderer} from 'angular2/render';
|
import {Renderer} from 'angular2/render';
|
||||||
import {Testability} from 'angular2/src/core/testability/testability';
|
import {Testability} from 'angular2/src/core/testability/testability';
|
||||||
|
|
||||||
// TODO change these imports once dom_adapter is moved out of core
|
|
||||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||||
import {DomEventsPlugin} from 'angular2/src/platform/dom/events/dom_events';
|
import {DomEventsPlugin} from 'angular2/src/platform/dom/events/dom_events';
|
||||||
import {KeyEventsPlugin} from 'angular2/src/platform/dom/events/key_events';
|
import {KeyEventsPlugin} from 'angular2/src/platform/dom/events/key_events';
|
||||||
@ -42,8 +42,10 @@ export {
|
|||||||
export {By} from 'angular2/src/platform/browser/debug/by';
|
export {By} from 'angular2/src/platform/browser/debug/by';
|
||||||
export {BrowserDomAdapter} from './browser/browser_adapter';
|
export {BrowserDomAdapter} from './browser/browser_adapter';
|
||||||
|
|
||||||
export const BROWSER_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
export const BROWSER_PROVIDERS: Array<any /*Type | Provider | any[]*/> = CONST_EXPR([
|
||||||
CONST_EXPR([PLATFORM_COMMON_PROVIDERS]);
|
PLATFORM_COMMON_PROVIDERS,
|
||||||
|
new Provider(PLATFORM_INITIALIZER, {useValue: initDomAdapter, multi: true}),
|
||||||
|
]);
|
||||||
|
|
||||||
function _exceptionHandler(): ExceptionHandler {
|
function _exceptionHandler(): ExceptionHandler {
|
||||||
return new ExceptionHandler(DOM, false);
|
return new ExceptionHandler(DOM, false);
|
||||||
@ -73,7 +75,6 @@ export const BROWSER_APP_COMMON_PROVIDERS: Array<any /*Type | Provider | any[]*/
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
export function initDomAdapter() {
|
export function initDomAdapter() {
|
||||||
// TODO: refactor into a generic init function
|
|
||||||
BrowserDomAdapter.makeCurrent();
|
BrowserDomAdapter.makeCurrent();
|
||||||
wtfInit();
|
wtfInit();
|
||||||
BrowserGetTestability.init();
|
BrowserGetTestability.init();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
AsyncTestCompleter,
|
AsyncTestCompleter,
|
||||||
beforeEach,
|
beforeEach,
|
||||||
|
afterEach,
|
||||||
ddescribe,
|
ddescribe,
|
||||||
describe,
|
describe,
|
||||||
expect,
|
expect,
|
||||||
@ -8,6 +9,7 @@ import {
|
|||||||
inject,
|
inject,
|
||||||
it,
|
it,
|
||||||
xdescribe,
|
xdescribe,
|
||||||
|
Log,
|
||||||
xit
|
xit
|
||||||
} from 'angular2/testing_internal';
|
} from 'angular2/testing_internal';
|
||||||
import {IS_DART, isPresent, stringify} from 'angular2/src/facade/lang';
|
import {IS_DART, isPresent, stringify} from 'angular2/src/facade/lang';
|
||||||
@ -18,7 +20,8 @@ import {BROWSER_PROVIDERS, BROWSER_APP_PROVIDERS} from 'angular2/platform/browse
|
|||||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||||
import {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens';
|
import {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens';
|
||||||
import {PromiseWrapper} from 'angular2/src/facade/async';
|
import {PromiseWrapper} from 'angular2/src/facade/async';
|
||||||
import {provide, Inject, Injector} from 'angular2/core';
|
import {provide, Inject, Injector, PLATFORM_INITIALIZER, APP_INITIALIZER} from 'angular2/core';
|
||||||
|
import {disposePlatform} from 'angular2/src/core/application_ref';
|
||||||
import {ExceptionHandler} from 'angular2/src/facade/exceptions';
|
import {ExceptionHandler} from 'angular2/src/facade/exceptions';
|
||||||
import {Testability, TestabilityRegistry} from 'angular2/src/core/testability/testability';
|
import {Testability, TestabilityRegistry} from 'angular2/src/core/testability/testability';
|
||||||
import {ComponentRef_} from "angular2/src/core/linker/dynamic_component_loader";
|
import {ComponentRef_} from "angular2/src/core/linker/dynamic_component_loader";
|
||||||
@ -101,6 +104,8 @@ export function main() {
|
|||||||
testProviders = [provide(DOCUMENT, {useValue: fakeDoc})];
|
testProviders = [provide(DOCUMENT, {useValue: fakeDoc})];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(disposePlatform);
|
||||||
|
|
||||||
it('should throw if bootstrapped Directive is not a Component',
|
it('should throw if bootstrapped Directive is not a Component',
|
||||||
inject([AsyncTestCompleter], (async) => {
|
inject([AsyncTestCompleter], (async) => {
|
||||||
var logger = new _ArrayLogger();
|
var logger = new _ArrayLogger();
|
||||||
@ -213,6 +218,23 @@ export function main() {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it("should run platform initializers", inject([Log], (log: Log) => {
|
||||||
|
let p = platform([
|
||||||
|
BROWSER_PROVIDERS,
|
||||||
|
provide(PLATFORM_INITIALIZER, {useValue: log.fn("platform_init1"), multi: true}),
|
||||||
|
provide(PLATFORM_INITIALIZER, {useValue: log.fn("platform_init2"), multi: true})
|
||||||
|
]);
|
||||||
|
expect(log.result()).toEqual("platform_init1; platform_init2");
|
||||||
|
log.clear();
|
||||||
|
p.application([
|
||||||
|
BROWSER_APP_PROVIDERS,
|
||||||
|
provide(APP_INITIALIZER, {useValue: log.fn("app_init1"), multi: true}),
|
||||||
|
provide(APP_INITIALIZER, {useValue: log.fn("app_init2"), multi: true})
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(log.result()).toEqual("app_init1; app_init2");
|
||||||
|
}));
|
||||||
|
|
||||||
it('should register each application with the testability registry',
|
it('should register each application with the testability registry',
|
||||||
inject([AsyncTestCompleter], (async) => {
|
inject([AsyncTestCompleter], (async) => {
|
||||||
var refPromise1 = bootstrap(HelloRootCmp, testProviders);
|
var refPromise1 = bootstrap(HelloRootCmp, testProviders);
|
||||||
|
@ -27,6 +27,7 @@ import {SymbolsDiff} from './symbol_inspector/symbol_differ';
|
|||||||
|
|
||||||
var NG_ALL = [
|
var NG_ALL = [
|
||||||
'APP_COMPONENT',
|
'APP_COMPONENT',
|
||||||
|
'APP_INITIALIZER',
|
||||||
'APP_ID',
|
'APP_ID',
|
||||||
'AbstractProviderError',
|
'AbstractProviderError',
|
||||||
'AbstractProviderError.addKey()',
|
'AbstractProviderError.addKey()',
|
||||||
@ -1396,6 +1397,7 @@ var NG_ALL = [
|
|||||||
'resolveForwardRef():js',
|
'resolveForwardRef():js',
|
||||||
'wtfCreateScope():js',
|
'wtfCreateScope():js',
|
||||||
'PLATFORM_COMMON_PROVIDERS',
|
'PLATFORM_COMMON_PROVIDERS',
|
||||||
|
'PLATFORM_INITIALIZER',
|
||||||
'wtfCreateScope:dart',
|
'wtfCreateScope:dart',
|
||||||
'wtfEndTimeRange():js',
|
'wtfEndTimeRange():js',
|
||||||
'wtfEndTimeRange:dart',
|
'wtfEndTimeRange:dart',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user