Skip to content

Commit 3c43a8c

Browse files
committed
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
1 parent 3fa287a commit 3c43a8c

9 files changed

Lines changed: 80 additions & 19 deletions

File tree

modules/angular2/core.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export 'package:angular2/src/common/pipes.dart';
99
export 'package:angular2/src/facade/facade.dart';
1010
export 'package:angular2/src/core/application_ref.dart'
1111
hide ApplicationRef_, PlatformRef_;
12+
export 'package:angular2/src/core/application_tokens.dart' show APP_ID, APP_COMPONENT, APP_INITIALIZER, PLATFORM_INITIALIZER;
1213
export 'package:angular2/src/core/linker.dart';
1314
export 'package:angular2/src/core/zone.dart';
1415
export 'package:angular2/src/core/render.dart';

modules/angular2/core.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ export * from './src/common/pipes';
1010
export * from './src/facade/facade';
1111
export * from './src/core/linker';
1212
export {platform, createNgZone, PlatformRef, ApplicationRef} from './src/core/application_ref';
13-
export {APP_ID, APP_COMPONENT} from './src/core/application_tokens';
13+
export {
14+
APP_ID,
15+
APP_COMPONENT,
16+
APP_INITIALIZER,
17+
PLATFORM_INITIALIZER
18+
} from './src/core/application_tokens';
1419
export * from './src/core/zone';
1520
export * from './src/core/render';
1621
export * from './src/common/directives';

modules/angular2/platform/browser.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ import {Type, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
1313
import {Promise} from 'angular2/src/facade/promise';
1414
import {
1515
BROWSER_PROVIDERS,
16-
BROWSER_APP_COMMON_PROVIDERS,
17-
initDomAdapter
16+
BROWSER_APP_COMMON_PROVIDERS
1817
} from 'angular2/src/platform/browser_common';
1918
import {COMPILER_PROVIDERS} from 'angular2/compiler';
2019
import {ComponentRef, platform, reflector} from 'angular2/core';
@@ -120,8 +119,6 @@ export function bootstrap(
120119
appComponentType: Type,
121120
customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ComponentRef> {
122121
reflector.reflectionCapabilities = new ReflectionCapabilities();
123-
initDomAdapter();
124-
125122
let appProviders =
126123
isPresent(customProviders) ? [BROWSER_APP_PROVIDERS, customProviders] : BROWSER_APP_PROVIDERS;
127124
return platform(BROWSER_PROVIDERS).application(appProviders).bootstrap(appComponentType);

modules/angular2/platform/browser_static.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import {Type, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
1212
import {Promise} from 'angular2/src/facade/promise';
1313
import {
1414
BROWSER_PROVIDERS,
15-
BROWSER_APP_COMMON_PROVIDERS,
16-
initDomAdapter
15+
BROWSER_APP_COMMON_PROVIDERS
1716
} from 'angular2/src/platform/browser_common';
1817
import {ComponentRef, platform, reflector} from 'angular2/core';
1918

@@ -31,7 +30,6 @@ export const BROWSER_APP_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
3130
export function bootstrapStatic(appComponentType: Type,
3231
customProviders?: Array<any /*Type | Provider | any[]*/>,
3332
initReflector?: Function): Promise<ComponentRef> {
34-
initDomAdapter();
3533
if (isPresent(initReflector)) {
3634
initReflector();
3735
}

modules/angular2/src/core/application_ref.ts

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import {provide, Provider, Injector, OpaqueToken} from 'angular2/src/core/di';
44
import {
55
APP_COMPONENT_REF_PROMISE,
66
APP_COMPONENT,
7-
APP_ID_RANDOM_PROVIDER
7+
APP_ID_RANDOM_PROVIDER,
8+
PLATFORM_INITIALIZER,
9+
APP_INITIALIZER
810
} from './application_tokens';
911
import {
1012
Promise,
@@ -30,7 +32,6 @@ import {wtfLeave, wtfCreateScope, WtfScopeFn} from './profile/profile';
3032
import {ChangeDetectorRef} from 'angular2/src/core/change_detection/change_detector_ref';
3133
import {lockDevMode} from 'angular2/src/facade/lang';
3234

33-
3435
/**
3536
* Construct providers specific to an individual root component.
3637
*/
@@ -103,15 +104,32 @@ export function platform(providers?: Array<Type | Provider | any[]>): PlatformRe
103104
}
104105
}
105106

107+
/**
108+
* Dispose the existing platform.
109+
*/
110+
export function disposePlatform(): void {
111+
if (isPresent(_platform)) {
112+
_platform.dispose();
113+
_platform = null;
114+
}
115+
}
116+
106117
function _createPlatform(providers?: Array<Type | Provider | any[]>): PlatformRef {
107118
_platformProviders = providers;
108-
_platform = new PlatformRef_(Injector.resolveAndCreate(providers), () => {
119+
let injector = Injector.resolveAndCreate(providers);
120+
_platform = new PlatformRef_(injector, () => {
109121
_platform = null;
110122
_platformProviders = null;
111123
});
124+
_runPlatformInitializers(injector);
112125
return _platform;
113126
}
114127

128+
function _runPlatformInitializers(injector: Injector): void {
129+
let inits: Function[] = injector.getOptional(PLATFORM_INITIALIZER);
130+
if (isPresent(inits)) inits.forEach(init => init());
131+
}
132+
115133
/**
116134
* The Angular platform is the entry point for Angular on a web page. Each page
117135
* has exactly one platform, and services (such as reflection) which are common
@@ -236,11 +254,12 @@ export class PlatformRef_ extends PlatformRef {
236254
});
237255
app = new ApplicationRef_(this, zone, injector);
238256
this._applications.push(app);
257+
_runAppInitializers(injector);
239258
return app;
240259
}
241260

242261
dispose(): void {
243-
this._applications.forEach((app) => app.dispose());
262+
ListWrapper.clone(this._applications).forEach((app) => app.dispose());
244263
this._disposeListeners.forEach((dispose) => dispose());
245264
this._dispose();
246265
}
@@ -249,6 +268,11 @@ export class PlatformRef_ extends PlatformRef {
249268
_applicationDisposed(app: ApplicationRef): void { ListWrapper.remove(this._applications, app); }
250269
}
251270

271+
function _runAppInitializers(injector: Injector): void {
272+
let inits: Function[] = injector.getOptional(APP_INITIALIZER);
273+
if (isPresent(inits)) inits.forEach(init => init());
274+
}
275+
252276
/**
253277
* A reference to an Angular application running on a page.
254278
*
@@ -439,7 +463,7 @@ export class ApplicationRef_ extends ApplicationRef {
439463

440464
dispose(): void {
441465
// TODO(alxhub): Dispose of the NgZone.
442-
this._rootComponents.forEach((ref) => ref.dispose());
466+
ListWrapper.clone(this._rootComponents).forEach((ref) => ref.dispose());
443467
this._disposeListeners.forEach((dispose) => dispose());
444468
this._platform._applicationDisposed(this);
445469
}

modules/angular2/src/core/application_tokens.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,14 @@ export const APP_ID_RANDOM_PROVIDER: Provider =
4848
function _randomChar(): string {
4949
return StringWrapper.fromCharCode(97 + Math.floor(Math.random() * 25));
5050
}
51+
52+
/**
53+
* A function that will be executed when a platform is initialized.
54+
*/
55+
export const PLATFORM_INITIALIZER: OpaqueToken =
56+
CONST_EXPR(new OpaqueToken("Platform Initializer"));
57+
58+
/**
59+
* A function that will be executed when an application is initialized.
60+
*/
61+
export const APP_INITIALIZER: OpaqueToken = CONST_EXPR(new OpaqueToken("Application Initializer"));

modules/angular2/src/platform/browser_common.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import {
1111
reflector,
1212
APPLICATION_COMMON_PROVIDERS,
1313
PLATFORM_COMMON_PROVIDERS,
14-
EVENT_MANAGER_PLUGINS
14+
EVENT_MANAGER_PLUGINS,
15+
PLATFORM_INITIALIZER
1516
} from "angular2/core";
1617
import {COMMON_DIRECTIVES, COMMON_PIPES, FORM_PROVIDERS} from "angular2/common";
1718
import {Renderer} from 'angular2/render';
1819
import {Testability} from 'angular2/src/core/testability/testability';
1920

20-
// TODO change these imports once dom_adapter is moved out of core
2121
import {DOM} from 'angular2/src/core/dom/dom_adapter';
2222
import {DomEventsPlugin} from 'angular2/src/platform/dom/events/dom_events';
2323
import {KeyEventsPlugin} from 'angular2/src/platform/dom/events/key_events';
@@ -42,8 +42,10 @@ export {
4242
export {By} from 'angular2/src/platform/browser/debug/by';
4343
export {BrowserDomAdapter} from './browser/browser_adapter';
4444

45-
export const BROWSER_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
46-
CONST_EXPR([PLATFORM_COMMON_PROVIDERS]);
45+
export const BROWSER_PROVIDERS: Array<any /*Type | Provider | any[]*/> = CONST_EXPR([
46+
PLATFORM_COMMON_PROVIDERS,
47+
new Provider(PLATFORM_INITIALIZER, {useValue: initDomAdapter, multi: true}),
48+
]);
4749

4850
function _exceptionHandler(): ExceptionHandler {
4951
return new ExceptionHandler(DOM, false);
@@ -73,7 +75,6 @@ export const BROWSER_APP_COMMON_PROVIDERS: Array<any /*Type | Provider | any[]*/
7375
]);
7476

7577
export function initDomAdapter() {
76-
// TODO: refactor into a generic init function
7778
BrowserDomAdapter.makeCurrent();
7879
wtfInit();
7980
BrowserGetTestability.init();

modules/angular2/test/platform/bootstrap_spec.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import {
22
AsyncTestCompleter,
33
beforeEach,
4+
afterEach,
45
ddescribe,
56
describe,
67
expect,
78
iit,
89
inject,
910
it,
1011
xdescribe,
12+
Log,
1113
xit
1214
} from 'angular2/testing_internal';
1315
import {IS_DART, isPresent, stringify} from 'angular2/src/facade/lang';
@@ -18,7 +20,8 @@ import {BROWSER_PROVIDERS, BROWSER_APP_PROVIDERS} from 'angular2/platform/browse
1820
import {DOM} from 'angular2/src/core/dom/dom_adapter';
1921
import {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens';
2022
import {PromiseWrapper} from 'angular2/src/facade/async';
21-
import {provide, Inject, Injector} from 'angular2/core';
23+
import {provide, Inject, Injector, PLATFORM_INITIALIZER, APP_INITIALIZER} from 'angular2/core';
24+
import {disposePlatform} from 'angular2/src/core/application_ref';
2225
import {ExceptionHandler} from 'angular2/src/facade/exceptions';
2326
import {Testability, TestabilityRegistry} from 'angular2/src/core/testability/testability';
2427
import {ComponentRef_} from "angular2/src/core/linker/dynamic_component_loader";
@@ -101,6 +104,8 @@ export function main() {
101104
testProviders = [provide(DOCUMENT, {useValue: fakeDoc})];
102105
});
103106

107+
afterEach(disposePlatform);
108+
104109
it('should throw if bootstrapped Directive is not a Component',
105110
inject([AsyncTestCompleter], (async) => {
106111
var logger = new _ArrayLogger();
@@ -213,6 +218,23 @@ export function main() {
213218
});
214219
}));
215220

221+
it("should run platform initializers", inject([Log], (log: Log) => {
222+
let p = platform([
223+
BROWSER_PROVIDERS,
224+
provide(PLATFORM_INITIALIZER, {useValue: log.fn("platform_init1"), multi: true}),
225+
provide(PLATFORM_INITIALIZER, {useValue: log.fn("platform_init2"), multi: true})
226+
]);
227+
expect(log.result()).toEqual("platform_init1; platform_init2");
228+
log.clear();
229+
p.application([
230+
BROWSER_APP_PROVIDERS,
231+
provide(APP_INITIALIZER, {useValue: log.fn("app_init1"), multi: true}),
232+
provide(APP_INITIALIZER, {useValue: log.fn("app_init2"), multi: true})
233+
]);
234+
235+
expect(log.result()).toEqual("app_init1; app_init2");
236+
}));
237+
216238
it('should register each application with the testability registry',
217239
inject([AsyncTestCompleter], (async) => {
218240
var refPromise1 = bootstrap(HelloRootCmp, testProviders);

modules/angular2/test/public_api_spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {SymbolsDiff} from './symbol_inspector/symbol_differ';
2727

2828
var NG_ALL = [
2929
'APP_COMPONENT',
30+
'APP_INITIALIZER',
3031
'APP_ID',
3132
'AbstractProviderError',
3233
'AbstractProviderError.addKey()',
@@ -1396,6 +1397,7 @@ var NG_ALL = [
13961397
'resolveForwardRef():js',
13971398
'wtfCreateScope():js',
13981399
'PLATFORM_COMMON_PROVIDERS',
1400+
'PLATFORM_INITIALIZER',
13991401
'wtfCreateScope:dart',
14001402
'wtfEndTimeRange():js',
14011403
'wtfEndTimeRange:dart',

0 commit comments

Comments
 (0)