feat(core): Add a long-form syntax for Angular bootstrapping.

This change adds a syntax for bootstrapping Angular on a page that allows more fine-grained control of the hierarchy created. platform() creates a platform injector (of which there can only be one). From the platform, .application() creates an Angular application including a Zone and all specified application bindings (e.g. for the DOM, HTTP, Compiler, Renderer, etc). At the application level, .bootstrap() will bootstrap the given component into that application.

Closes #3852
This commit is contained in:
Alex Rickabaugh 2015-09-02 15:19:26 -07:00
parent 193792c27f
commit 97d1844bfc
16 changed files with 503 additions and 408 deletions

View File

@ -5,9 +5,9 @@ export 'package:angular2/src/core/util.dart';
export 'package:angular2/src/core/di.dart'; export 'package:angular2/src/core/di.dart';
export 'package:angular2/src/core/pipes.dart'; export 'package:angular2/src/core/pipes.dart';
export 'package:angular2/src/core/facade.dart'; export 'package:angular2/src/core/facade.dart';
export 'package:angular2/src/core/application_ref.dart';
// Do not export application for dart. Must import from angular2/bootstrap // Do not export application for dart. Must import from angular2/bootstrap
//export 'package:angular2/src/core/application.dart'; //export 'package:angular2/src/core/application.dart';
export 'package:angular2/src/core/application_ref.dart';
export 'package:angular2/src/core/services.dart'; export 'package:angular2/src/core/services.dart';
export 'package:angular2/src/core/compiler.dart'; export 'package:angular2/src/core/compiler.dart';
export 'package:angular2/src/core/lifecycle.dart'; export 'package:angular2/src/core/lifecycle.dart';

View File

@ -6,9 +6,9 @@ import 'package:angular2/src/core/reflection/reflection.dart' show reflector;
import 'package:angular2/src/core/reflection/reflection_capabilities.dart' import 'package:angular2/src/core/reflection/reflection_capabilities.dart'
show ReflectionCapabilities; show ReflectionCapabilities;
import 'application_common.dart'; import 'application_common.dart';
import 'application_ref.dart';
export 'application_ref.dart' show ApplicationRef; import 'package:angular2/src/core/compiler/dynamic_component_loader.dart';
export 'package:angular2/src/core/compiler/dynamic_component_loader.dart' show ComponentRef;
/// Starts an application from a root component. This implementation uses /// Starts an application from a root component. This implementation uses
/// mirrors. Angular 2 transformer automatically replaces this method with a /// mirrors. Angular 2 transformer automatically replaces this method with a
@ -16,7 +16,7 @@ export 'application_ref.dart' show ApplicationRef;
/// mirrors and produces a faster and more compact JS code. /// mirrors and produces a faster and more compact JS code.
/// ///
/// See [commonBootstrap] for detailed documentation. /// See [commonBootstrap] for detailed documentation.
Future<ApplicationRef> bootstrap(Type appComponentType, Future<ComponentRef> bootstrap(Type appComponentType,
[List componentInjectableBindings]) { [List componentInjectableBindings]) {
reflector.reflectionCapabilities = new ReflectionCapabilities(); reflector.reflectionCapabilities = new ReflectionCapabilities();
return commonBootstrap(appComponentType, componentInjectableBindings); return commonBootstrap(appComponentType, componentInjectableBindings);

View File

@ -1,3 +1,4 @@
// Public API for Application // Public API for Application
export {ApplicationRef} from './application_ref';
export {APP_COMPONENT} from './application_tokens'; export {APP_COMPONENT} from './application_tokens';
export {platform, commonBootstrap as bootstrap} from './application_common';
export {PlatformRef, ApplicationRef, rootBindings} from './application_ref';

View File

@ -1,4 +1,3 @@
import {DEFAULT_PIPES} from 'angular2/src/core/pipes';
import {FORM_BINDINGS} from 'angular2/src/core/forms'; import {FORM_BINDINGS} from 'angular2/src/core/forms';
import {bind, Binding, Injector, OpaqueToken} from 'angular2/src/core/di'; import {bind, Binding, Injector, OpaqueToken} from 'angular2/src/core/di';
import { import {
@ -10,37 +9,12 @@ import {
print, print,
stringify stringify
} from 'angular2/src/core/facade/lang'; } from 'angular2/src/core/facade/lang';
import {
BaseException,
WrappedException,
ExceptionHandler
} from 'angular2/src/core/facade/exceptions';
import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter'; import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter';
import {BrowserGetTestability} from 'angular2/src/core/testability/browser_testability';
import {DOM} from 'angular2/src/core/dom/dom_adapter'; import {DOM} from 'angular2/src/core/dom/dom_adapter';
import {Compiler, CompilerCache} from './compiler/compiler';
import {Reflector, reflector} from 'angular2/src/core/reflection/reflection';
import {
Parser,
Lexer,
ChangeDetection,
DynamicChangeDetection,
JitChangeDetection,
PreGeneratedChangeDetection,
IterableDiffers,
defaultIterableDiffers,
KeyValueDiffers,
defaultKeyValueDiffers
} from 'angular2/src/core/change_detection/change_detection';
import {ViewLoader} from 'angular2/src/core/render/dom/compiler/view_loader'; import {ViewLoader} from 'angular2/src/core/render/dom/compiler/view_loader';
import {StyleUrlResolver} from 'angular2/src/core/render/dom/compiler/style_url_resolver';
import {StyleInliner} from 'angular2/src/core/render/dom/compiler/style_inliner'; import {StyleInliner} from 'angular2/src/core/render/dom/compiler/style_inliner';
import {ViewResolver} from './compiler/view_resolver';
import {DirectiveResolver} from './compiler/directive_resolver';
import {PipeResolver} from './compiler/pipe_resolver';
import {ListWrapper} from 'angular2/src/core/facade/collection';
import {Promise, PromiseWrapper, PromiseCompleter} from 'angular2/src/core/facade/async'; import {Promise, PromiseWrapper, PromiseCompleter} from 'angular2/src/core/facade/async';
import {NgZone} from 'angular2/src/core/zone/ng_zone';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {XHR} from 'angular2/src/core/render/xhr'; import {XHR} from 'angular2/src/core/render/xhr';
import {XHRImpl} from 'angular2/src/core/render/xhr_impl'; import {XHRImpl} from 'angular2/src/core/render/xhr_impl';
import { import {
@ -50,8 +24,6 @@ import {
} from 'angular2/src/core/render/dom/events/event_manager'; } from 'angular2/src/core/render/dom/events/event_manager';
import {KeyEventsPlugin} from 'angular2/src/core/render/dom/events/key_events'; import {KeyEventsPlugin} from 'angular2/src/core/render/dom/events/key_events';
import {HammerGesturesPlugin} from 'angular2/src/core/render/dom/events/hammer_gestures'; import {HammerGesturesPlugin} from 'angular2/src/core/render/dom/events/hammer_gestures';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
import {AppRootUrl} from 'angular2/src/core/services/app_root_url'; import {AppRootUrl} from 'angular2/src/core/services/app_root_url';
import {AnchorBasedAppRootUrl} from 'angular2/src/core/services/anchor_based_app_root_url'; import {AnchorBasedAppRootUrl} from 'angular2/src/core/services/anchor_based_app_root_url';
import { import {
@ -59,11 +31,6 @@ import {
DynamicComponentLoader DynamicComponentLoader
} from 'angular2/src/core/compiler/dynamic_component_loader'; } from 'angular2/src/core/compiler/dynamic_component_loader';
import {TestabilityRegistry, Testability} from 'angular2/src/core/testability/testability'; import {TestabilityRegistry, Testability} from 'angular2/src/core/testability/testability';
import {AppViewPool, APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool';
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
import {Renderer, RenderCompiler} from 'angular2/src/core/render/api'; import {Renderer, RenderCompiler} from 'angular2/src/core/render/api';
import { import {
DomRenderer, DomRenderer,
@ -81,46 +48,23 @@ import {
SharedStylesHost, SharedStylesHost,
DomSharedStylesHost DomSharedStylesHost
} from 'angular2/src/core/render/dom/view/shared_styles_host'; } from 'angular2/src/core/render/dom/view/shared_styles_host';
import {internalView} from 'angular2/src/core/compiler/view_ref';
import {APP_COMPONENT_REF_PROMISE, APP_COMPONENT} from './application_tokens';
import {wtfInit} from './profile/wtf_init';
import {EXCEPTION_BINDING} from './platform_bindings'; import {EXCEPTION_BINDING} from './platform_bindings';
import {ApplicationRef} from './application_ref';
import {AnimationBuilder} from 'angular2/src/animate/animation_builder'; import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
import {BrowserDetails} from 'angular2/src/animate/browser_details'; import {BrowserDetails} from 'angular2/src/animate/browser_details';
import {wtfInit} from './profile/wtf_init';
import {platformCommon, PlatformRef, applicationCommonBindings} from './application_ref';
var _rootInjector: Injector; /**
* A default set of bindings which apply only to an Angular application running on
// Contains everything that is safe to share between applications. * the UI thread.
var _rootBindings = [bind(Reflector).toValue(reflector), TestabilityRegistry]; */
export function applicationDomBindings(): Array<Type | Binding | any[]> {
function _injectorBindings(appComponentType): Array<Type | Binding | any[]> { if (isBlank(DOM)) {
var bestChangeDetection = new DynamicChangeDetection(); throw "Must set a root DOM adapter first.";
if (PreGeneratedChangeDetection.isSupported()) {
bestChangeDetection = new PreGeneratedChangeDetection();
} else if (JitChangeDetection.isSupported()) {
bestChangeDetection = new JitChangeDetection();
} }
return [ return [
bind(DOCUMENT) bind(DOCUMENT)
.toValue(DOM.defaultDoc()), .toValue(DOM.defaultDoc()),
bind(APP_COMPONENT).toValue(appComponentType),
bind(APP_COMPONENT_REF_PROMISE)
.toFactory(
(dynamicComponentLoader, injector, testability, registry) => {
// TODO(rado): investigate whether to support bindings on root component.
return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector)
.then((componentRef) => {
registry.registerApplication(componentRef.location.nativeElement, testability);
return componentRef;
});
},
[DynamicComponentLoader, Injector, Testability, TestabilityRegistry]),
bind(appComponentType)
.toFactory((p: Promise<any>) => p.then(ref => ref.instance), [APP_COMPONENT_REF_PROMISE]),
bind(LifeCycle).toFactory((exceptionHandler) => new LifeCycle(null, assertionsEnabled()),
[ExceptionHandler]),
EventManager, EventManager,
new Binding(EVENT_MANAGER_PLUGINS, {toClass: DomEventsPlugin, multi: true}), new Binding(EVENT_MANAGER_PLUGINS, {toClass: DomEventsPlugin, multi: true}),
new Binding(EVENT_MANAGER_PLUGINS, {toClass: KeyEventsPlugin, multi: true}), new Binding(EVENT_MANAGER_PLUGINS, {toClass: KeyEventsPlugin, multi: true}),
@ -135,31 +79,10 @@ function _injectorBindings(appComponentType): Array<Type | Binding | any[]> {
bind(RenderCompiler).toAlias(DefaultDomCompiler), bind(RenderCompiler).toAlias(DefaultDomCompiler),
DomSharedStylesHost, DomSharedStylesHost,
bind(SharedStylesHost).toAlias(DomSharedStylesHost), bind(SharedStylesHost).toAlias(DomSharedStylesHost),
ProtoViewFactory,
AppViewPool,
bind(APP_VIEW_POOL_CAPACITY).toValue(10000),
AppViewManager,
AppViewManagerUtils,
AppViewListener,
Compiler,
CompilerCache,
ViewResolver,
DEFAULT_PIPES,
bind(IterableDiffers).toValue(defaultIterableDiffers),
bind(KeyValueDiffers).toValue(defaultKeyValueDiffers),
bind(ChangeDetection).toValue(bestChangeDetection),
ViewLoader, ViewLoader,
DirectiveResolver,
PipeResolver,
Parser,
Lexer,
EXCEPTION_BINDING, EXCEPTION_BINDING,
bind(XHR).toValue(new XHRImpl()), bind(XHR).toValue(new XHRImpl()),
ComponentUrlMapper,
UrlResolver,
StyleUrlResolver,
StyleInliner, StyleInliner,
DynamicComponentLoader,
Testability, Testability,
AnchorBasedAppRootUrl, AnchorBasedAppRootUrl,
bind(AppRootUrl).toAlias(AnchorBasedAppRootUrl), bind(AppRootUrl).toAlias(AnchorBasedAppRootUrl),
@ -169,16 +92,28 @@ function _injectorBindings(appComponentType): Array<Type | Binding | any[]> {
]; ];
} }
export function createNgZone(): NgZone {
return new NgZone({enableLongStackTrace: assertionsEnabled()});
/**
* Initialize the Angular context on the page.
*
* If no bindings are provided, calling {@link platform}() is idempotent,
* and will use the default platform bindings (which can be obtained from
* {@link rootBindings}).
*/
export function platform(bindings?: Array<Type | Binding | any[]>): PlatformRef {
return platformCommon(bindings, () => {
BrowserDomAdapter.makeCurrent();
wtfInit();
BrowserGetTestability.init();
});
} }
/** /**
* Bootstrapping for Angular applications. * Bootstrapping for Angular applications.
* *
* You instantiate an Angular application by explicitly specifying a component to use as the root * You instantiate an Angular application by explicitly specifying a component to use
* component for your * as the root component for your application via the `bootstrap()` method.
* application via the `bootstrap()` method.
* *
* ## Simple Example * ## Simple Example
* *
@ -193,15 +128,12 @@ export function createNgZone(): NgZone {
* </html> * </html>
* ``` * ```
* *
* An application is bootstrapped inside an existing browser DOM, typically `index.html`. Unlike * An application is bootstrapped inside an existing browser DOM, typically `index.html`.
* Angular 1, Angular 2 * Unlike Angular 1, Angular 2 does not compile/process bindings in `index.html`. This is
* does not compile/process bindings in `index.html`. This is mainly for security reasons, as well * mainly for security reasons, as well as architectural changes in Angular 2. This means
* as architectural * that `index.html` can safely be processed using server-side technologies such as
* changes in Angular 2. This means that `index.html` can safely be processed using server-side * bindings. Bindings can thus use double-curly `{{ syntax }}` without collision from
* technologies such as * Angular 2 component double-curly `{{ syntax }}`.
* bindings. Bindings can thus use double-curly `{{ syntax }}` without collision from Angular 2
* component double-curly
* `{{ syntax }}`.
* *
* We can use this script code: * We can use this script code:
* *
@ -225,20 +157,18 @@ export function createNgZone(): NgZone {
* } * }
* ``` * ```
* *
* When the app developer invokes `bootstrap()` with the root component `MyApp` as its argument, * When the app developer invokes `bootstrap()` with the root component `MyApp` as its
* Angular performs the * argument, Angular performs the following tasks:
* following tasks:
* *
* 1. It uses the component's `selector` property to locate the DOM element which needs to be * 1. It uses the component's `selector` property to locate the DOM element which needs
* upgraded into * to be upgraded into the angular component.
* the angular component. * 2. It creates a new child injector (from the platform injector). Optionally, you can
* 2. It creates a new child injector (from the platform injector). Optionally, you can also * also override the injector configuration for an app by invoking `bootstrap` with the
* override the injector configuration for an app by * `componentInjectableBindings` argument.
* invoking `bootstrap` with the `componentInjectableBindings` argument. * 3. It creates a new `Zone` and connects it to the angular application's change detection
* 3. It creates a new `Zone` and connects it to the angular application's change detection domain * domain instance.
* instance. * 4. It creates a shadow DOM on the selected component's host element and loads the
* 4. It creates a shadow DOM on the selected component's host element and loads the template into * template into it.
* it.
* 5. It instantiates the specified component. * 5. It instantiates the specified component.
* 6. Finally, Angular performs change detection to apply the initial data bindings for the * 6. Finally, Angular performs change detection to apply the initial data bindings for the
* application. * application.
@ -248,111 +178,56 @@ export function createNgZone(): NgZone {
* *
* There are two ways to do this. * There are two ways to do this.
* *
*
* ### Isolated Applications * ### Isolated Applications
* *
* Angular creates a new application each time that the `bootstrap()` method is invoked. When * Angular creates a new application each time that the `bootstrap()` method is invoked.
* multiple applications * When multiple applications are created for a page, Angular treats each application as
* are created for a page, Angular treats each application as independent within an isolated change * independent within an isolated change detection and `Zone` domain. If you need to share
* detection and * data between applications, use the strategy described in the next section, "Applications
* `Zone` domain. If you need to share data between applications, use the strategy described in the * That Share Change Detection."
* next
* section, "Applications That Share Change Detection."
* *
* *
* ### Applications That Share Change Detection * ### Applications That Share Change Detection
* *
* If you need to bootstrap multiple applications that share common data, the applications must * If you need to bootstrap multiple applications that share common data, the applications
* share a common * must share a common change detection and zone. To do that, create a meta-component that
* change detection and zone. To do that, create a meta-component that lists the application * lists the application components in its template.
* components in its template. *
* By only invoking the `bootstrap()` method once, with the meta-component as its argument, you * By only invoking the `bootstrap()` method once, with the meta-component as its argument,
* ensure that only a * you ensure that only a single change detection zone is created and therefore data can be
* single change detection zone is created and therefore data can be shared across the applications. * shared across the applications.
* *
* *
* ## Platform Injector * ## Platform Injector
* *
* When working within a browser window, there are many singleton resources: cookies, title, * When working within a browser window, there are many singleton resources: cookies, title,
* location, and others. * location, and others. Angular services that represent these resources must likewise be
* Angular services that represent these resources must likewise be shared across all Angular * shared across all Angular applications that occupy the same browser window. For this
* applications that * reason, Angular creates exactly one global platform injector which stores all shared
* occupy the same browser window. For this reason, Angular creates exactly one global platform * services, and each angular application injector has the platform injector as its parent.
* injector which stores
* all shared services, and each angular application injector has the platform injector as its
* parent.
* *
* Each application has its own private injector as well. When there are multiple applications on a * Each application has its own private injector as well. When there are multipl
* page, Angular treats * applications on a page, Angular treats each application injector's services as private
* each application injector's services as private to that application. * to that application.
* *
* *
* # API * # API
* - `appComponentType`: The root component which should act as the application. This is a reference * - `appComponentType`: The root component which should act as the application. This is
* to a `Type` * a reference to a `Type` which is annotated with `@Component(...)`.
* which is annotated with `@Component(...)`. * - `componentInjectableBindings`: An additional set of bindings that can be added to the
* - `componentInjectableBindings`: An additional set of bindings that can be added to the app * app injector to override default injection behavior.
* injector * - `errorReporter`: `function(exception:any, stackTrace:string)` a default error reporter
* to override default injection behavior. * for unhandled exceptions.
* - `errorReporter`: `function(exception:any, stackTrace:string)` a default error reporter for
* unhandled exceptions.
* *
* Returns a `Promise` of {@link ApplicationRef}. * Returns a `Promise` of {@link ApplicationRef}.
*/ */
export function commonBootstrap(appComponentType: /*Type*/ any, export function commonBootstrap(appComponentType: /*Type*/ any,
componentInjectableBindings: Array<Type | Binding | any[]> = null): appBindings: Array<Type | Binding | any[]> = null):
Promise<ApplicationRef> { Promise<ComponentRef> {
BrowserDomAdapter.makeCurrent(); var p = platform();
wtfInit(); var bindings = [applicationCommonBindings(), applicationDomBindings()];
var bootstrapProcess = PromiseWrapper.completer(); if (isPresent(appBindings)) {
var zone = createNgZone(); bindings.push(appBindings);
zone.run(() => {
var exceptionHandler;
try {
var appInjector = _createAppInjector(appComponentType, componentInjectableBindings, zone);
exceptionHandler = appInjector.get(ExceptionHandler);
zone.overrideOnErrorHandler((e, s) => exceptionHandler.call(e, s));
var compRefToken: Promise<any> = appInjector.get(APP_COMPONENT_REF_PROMISE);
var tick = (componentRef) => {
var appChangeDetector = internalView(componentRef.hostView).changeDetector;
// retrieve life cycle: may have already been created if injected in root component
var lc = appInjector.get(LifeCycle);
lc.registerWith(zone, appChangeDetector);
lc.tick(); // the first tick that will bootstrap the app
bootstrapProcess.resolve(new ApplicationRef(componentRef, appComponentType, appInjector));
};
var tickResult = PromiseWrapper.then(compRefToken, tick);
PromiseWrapper.then(tickResult,
(_) => {}); // required for Dart to trigger the default error handler
PromiseWrapper.then(tickResult, null,
(err, stackTrace) => { bootstrapProcess.reject(err, stackTrace); });
} catch (e) {
if (isPresent(exceptionHandler)) {
exceptionHandler.call(e, e.stack);
} else {
// The error happened during the creation of an injector, most likely because of a bug in
// DI.
// We cannot use the provided exception handler, so we default to writing to the DOM.
DOM.logError(e);
} }
bootstrapProcess.reject(e, e.stack); return p.application(bindings).bootstrap(appComponentType);
}
});
return bootstrapProcess.promise;
}
function _createAppInjector(appComponentType: Type, bindings: Array<Type | Binding | any[]>,
zone: NgZone): Injector {
if (isBlank(_rootInjector)) _rootInjector = Injector.resolveAndCreate(_rootBindings);
var mergedBindings: any[] =
isPresent(bindings) ? ListWrapper.concat(_injectorBindings(appComponentType), bindings) :
_injectorBindings(appComponentType);
mergedBindings.push(bind(NgZone).toValue(zone));
return _rootInjector.resolveAndCreateChild(mergedBindings);
} }

View File

@ -1,47 +1,320 @@
import {ComponentRef} from 'angular2/src/core/compiler/dynamic_component_loader';
import {Injector} from 'angular2/src/core/di'; import {NgZone} from 'angular2/src/core/zone/ng_zone';
import {Type} from 'angular2/src/core/facade/lang'; import {Type, isBlank, isPresent, assertionsEnabled} from 'angular2/src/core/facade/lang';
import {bind, Binding, Injector, OpaqueToken} from 'angular2/src/core/di';
import {APP_COMPONENT_REF_PROMISE, APP_COMPONENT} from './application_tokens';
import {Promise, PromiseWrapper, PromiseCompleter} from 'angular2/src/core/facade/async';
import {ListWrapper} from 'angular2/src/core/facade/collection';
import {Reflector, reflector} from 'angular2/src/core/reflection/reflection';
import {TestabilityRegistry, Testability} from 'angular2/src/core/testability/testability';
import {
ComponentRef,
DynamicComponentLoader
} from 'angular2/src/core/compiler/dynamic_component_loader';
import {
BaseException,
WrappedException,
ExceptionHandler
} from 'angular2/src/core/facade/exceptions';
import {DOM} from 'angular2/src/core/dom/dom_adapter';
import {internalView} from 'angular2/src/core/compiler/view_ref';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
import {
Parser,
Lexer,
ChangeDetection,
DynamicChangeDetection,
JitChangeDetection,
PreGeneratedChangeDetection,
IterableDiffers,
defaultIterableDiffers,
KeyValueDiffers,
defaultKeyValueDiffers
} from 'angular2/src/core/change_detection/change_detection';
import {AppViewPool, APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool';
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
import {Compiler, CompilerCache} from './compiler/compiler';
import {DEFAULT_PIPES} from 'angular2/src/core/pipes';
import {ViewResolver} from './compiler/view_resolver';
import {DirectiveResolver} from './compiler/directive_resolver';
import {PipeResolver} from './compiler/pipe_resolver';
import {StyleUrlResolver} from 'angular2/src/core/render/dom/compiler/style_url_resolver';
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
/** /**
* Represents a Angular's representation of an Application. * Contains everything that is safe to share between applications.
*
* `ApplicationRef` represents a running application instance. Use it to retrieve the host
* component, injector,
* or dispose of an application.
*/ */
export class ApplicationRef { export function rootBindings(): Array<Type | Binding | any[]> {
_hostComponent: ComponentRef; return [bind(Reflector).toValue(reflector), TestabilityRegistry];
_injector: Injector; }
_hostComponentType: Type;
/**
* Construct bindings specific to an individual root component.
*/
function _componentBindings(appComponentType: Type): Array<Type | Binding | any[]> {
return [
bind(APP_COMPONENT)
.toValue(appComponentType),
bind(APP_COMPONENT_REF_PROMISE)
.toFactory(
(dynamicComponentLoader, injector: Injector) => {
// TODO(rado): investigate whether to support bindings on root component.
return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector)
.then((componentRef) => {
if (isPresent(componentRef.location.nativeElement)) {
injector.get(TestabilityRegistry)
.registerApplication(componentRef.location.nativeElement,
injector.get(Testability));
}
return componentRef;
});
},
[DynamicComponentLoader, Injector]),
bind(appComponentType)
.toFactory((p: Promise<any>) => p.then(ref => ref.instance), [APP_COMPONENT_REF_PROMISE]),
];
}
/**
* Construct a default set of bindings which should be included in any Angular
* application, regardless of whether it runs on the UI thread or in a web worker.
*/
export function applicationCommonBindings(): Array<Type | Binding | any[]> {
var bestChangeDetection = new DynamicChangeDetection();
if (PreGeneratedChangeDetection.isSupported()) {
bestChangeDetection = new PreGeneratedChangeDetection();
} else if (JitChangeDetection.isSupported()) {
bestChangeDetection = new JitChangeDetection();
}
return [
ProtoViewFactory,
AppViewPool,
bind(APP_VIEW_POOL_CAPACITY).toValue(10000),
AppViewManager,
AppViewManagerUtils,
AppViewListener,
Compiler,
CompilerCache,
ViewResolver,
DEFAULT_PIPES,
bind(IterableDiffers).toValue(defaultIterableDiffers),
bind(KeyValueDiffers).toValue(defaultKeyValueDiffers),
bind(ChangeDetection).toValue(bestChangeDetection),
DirectiveResolver,
UrlResolver,
StyleUrlResolver,
PipeResolver,
ComponentUrlMapper,
Parser,
Lexer,
DynamicComponentLoader,
bind(LifeCycle).toFactory((exceptionHandler) => new LifeCycle(null, assertionsEnabled()),
[ExceptionHandler]),
];
}
/**
* Create an Angular zone.
*/
export function createNgZone(): NgZone {
return new NgZone({enableLongStackTrace: assertionsEnabled()});
}
var _platform: PlatformRef;
/**
* @private
*/
export function platformCommon(bindings?: Array<Type | Binding | any[]>, initializer?: () => void):
PlatformRef {
if (isPresent(_platform)) {
if (isBlank(bindings)) {
return _platform;
}
throw "platform() can only be called once per page";
}
if (isPresent(initializer)) {
initializer();
}
if (isBlank(bindings)) {
bindings = rootBindings();
}
_platform = new PlatformRef(Injector.resolveAndCreate(bindings), () => { _platform = null; });
return _platform;
}
/**
* Represent the Angular context on a page, and is a true singleton.
*
* The platform {@link Injector} injects dependencies which are also
* truly singletons in the context of a page (such as the browser's
* cookie jar).
*/
export class PlatformRef {
/**
* @private
*/
_applications: ApplicationRef[] = [];
/** /**
* @private * @private
*/ */
constructor(hostComponent: ComponentRef, hostComponentType: Type, injector: Injector) { constructor(private _injector: Injector, private _dispose: () => void) {}
this._hostComponent = hostComponent;
this._injector = injector;
this._hostComponentType = hostComponentType;
}
/** /**
* Returns the current {@link ComponentMetadata} type. * Get the platform {@link Injector}.
*/
get hostComponentType(): Type { return this._hostComponentType; }
/**
* Returns the current {@link ComponentMetadata} instance.
*/
get hostComponent(): any { return this._hostComponent.instance; }
/**
* Dispose (un-load) the application.
*/
dispose(): void {
// TODO: We also need to clean up the Zone, ... here!
this._hostComponent.dispose();
}
/**
* Returns the root application {@link Injector}.
*/ */
get injector(): Injector { return this._injector; } get injector(): Injector { return this._injector; }
/**
* Build a new Angular application with the given bindings. The `ApplicationRef`
* returned can be used to bootstrap one or more root components within the
* application.
*/
application(bindings: Array<Type | Binding | any[]>): ApplicationRef {
var app = this._initApp(createNgZone(), bindings);
return app;
}
/**
* Build a new Angular application from asynchronously provided bindings.
*
* Runs the `AsyncLoader` callback in the application `Zone` and constructs
* a new Application from the bindings provided by the `Promise` it returns.
*/
asyncApplication(bindingFn: (zone: NgZone) =>
Promise<Array<Type | Binding | any[]>>): Promise<ApplicationRef> {
var zone = createNgZone();
var completer = PromiseWrapper.completer();
zone.run(() => {
PromiseWrapper.then(bindingFn(zone), (bindings: Array<Type | Binding | any[]>) => {
completer.resolve(this._initApp(zone, bindings));
});
});
return completer.promise;
}
private _initApp(zone: NgZone, bindings: Array<Type | Binding | any[]>): ApplicationRef {
var injector: Injector;
zone.run(() => {
bindings.push(bind(NgZone).toValue(zone));
bindings.push(bind(ApplicationRef).toValue(this));
var exceptionHandler;
try {
injector = this.injector.resolveAndCreateChild(bindings);
exceptionHandler = injector.get(ExceptionHandler);
zone.overrideOnErrorHandler((e, s) => exceptionHandler.call(e, s));
} catch (e) {
if (isPresent(exceptionHandler)) {
exceptionHandler.call(e, e.stack);
} else {
DOM.logError(e);
}
}
});
var app = new ApplicationRef(this, zone, injector);
this._applications.push(app);
return app;
}
/**
* Destroy the Angular platform and all Angular applications on the page.
*/
dispose(): void {
this._applications.forEach((app) => app.dispose());
this._dispose();
}
/**
* @private
*/
_applicationDisposed(app: ApplicationRef): void { ListWrapper.remove(this._applications, app); }
}
/**
* Represents an Angular application.
*
* Use to retrieve the application {@link Injector} or to bootstrap new
* components at the root of the application. Can also be used to dispose
* of the entire application and all its loaded components.
*/
export class ApplicationRef {
private _bootstrapListeners: Function[] = [];
private _rootComponents: ComponentRef[] = [];
/**
* @private
*/
constructor(private _platform: PlatformRef, private _zone: NgZone, private _injector: Injector) {}
/**
* Register a listener to be called each time a new root component type is bootstrapped.
*/
registerBootstrapListener(listener: (ref: ComponentRef) => void): void {
this._bootstrapListeners.push(listener);
}
/**
* Bootstrap a new component at the root level of the application, optionally with
* component specific bindings.
*/
bootstrap(componentType: Type, bindings?: Array<Type | Binding | any[]>): Promise<ComponentRef> {
var completer = PromiseWrapper.completer();
this._zone.run(() => {
var componentBindings = _componentBindings(componentType);
if (isPresent(bindings)) {
componentBindings.push(bindings);
}
var exceptionHandler = this._injector.get(ExceptionHandler);
try {
var injector: Injector = this._injector.resolveAndCreateChild(componentBindings);
var compRefToken: Promise<ComponentRef> = injector.get(APP_COMPONENT_REF_PROMISE);
var tick = (componentRef) => {
var appChangeDetector = internalView(componentRef.hostView).changeDetector;
var lc = injector.get(LifeCycle);
lc.registerWith(this._zone, appChangeDetector);
lc.tick();
completer.resolve(componentRef);
this._rootComponents.push(componentRef);
this._bootstrapListeners.forEach((listener) => listener(componentRef));
};
var tickResult = PromiseWrapper.then(compRefToken, tick);
PromiseWrapper.then(tickResult, (_) => {});
PromiseWrapper.then(tickResult, null,
(err, stackTrace) => completer.reject(err, stackTrace));
} catch (e) {
exceptionHandler.call(e, e.stack);
completer.reject(e, e.stack);
}
});
return completer.promise;
}
/**
* Retrieve the application {@link Injector}.
*/
get injector(): Injector { return this._injector; }
/**
* Retrieve the application {@link Zone}.
*/
get zone(): NgZone { return this._zone; }
dispose(): void {
// TODO(alxhub): Dispose of the NgZone.
this._rootComponents.forEach((ref) => ref.dispose());
this._platform._applicationDisposed(this);
}
} }

View File

@ -2,12 +2,12 @@ library angular2.src.core.application_static;
import 'dart:async'; import 'dart:async';
import 'application_common.dart'; import 'application_common.dart';
import 'application_ref.dart'; import 'package:angular2/src/core/compiler/dynamic_component_loader.dart' show ComponentRef;
/// Starts an application from a root component. /// Starts an application from a root component.
/// ///
/// See [commonBootstrap] for detailed documentation. /// See [commonBootstrap] for detailed documentation.
Future<ApplicationRef> bootstrapStatic(Type appComponentType, Future<ComponentRef> bootstrapStatic(Type appComponentType,
[List componentInjectableBindings, void initReflector()]) { [List componentInjectableBindings, void initReflector()]) {
if (initReflector != null) { if (initReflector != null) {
initReflector(); initReflector();

View File

@ -2,7 +2,7 @@ library angular2.src.core.bootstrap;
import 'dart:async'; import 'dart:async';
import 'application_ref.dart'; import 'package:angular2/src/core/compiler/dynamic_component_loader.dart' show ComponentRef;
import 'package:angular2/src/core/reflection/reflection.dart' show reflector; import 'package:angular2/src/core/reflection/reflection.dart' show reflector;
import 'package:angular2/src/core/reflection/reflection_capabilities.dart' import 'package:angular2/src/core/reflection/reflection_capabilities.dart'
show ReflectionCapabilities; show ReflectionCapabilities;
@ -14,7 +14,7 @@ import 'application_common.dart';
/// mirrors and produces a faster and more compact JS code. /// mirrors and produces a faster and more compact JS code.
/// ///
/// See [commonBootstrap] for detailed documentation. /// See [commonBootstrap] for detailed documentation.
Future<ApplicationRef> bootstrap(Type appComponentType, Future<ComponentRef> bootstrap(Type appComponentType,
[List componentInjectableBindings]) { [List componentInjectableBindings]) {
reflector.reflectionCapabilities = new ReflectionCapabilities(); reflector.reflectionCapabilities = new ReflectionCapabilities();
return commonBootstrap(appComponentType, componentInjectableBindings); return commonBootstrap(appComponentType, componentInjectableBindings);

View File

@ -1,11 +1,15 @@
import {Key, Injector, ResolvedBinding, Binding, bind, Injectable} from 'angular2/src/core/di'; import {Key, Injector, ResolvedBinding, Binding, bind, Injectable} from 'angular2/src/core/di';
import {Compiler} from './compiler'; import {Compiler} from './compiler';
import {Type, stringify, isPresent} from 'angular2/src/core/facade/lang'; import {isType, Type, stringify, isPresent} from 'angular2/src/core/facade/lang';
import {Promise} from 'angular2/src/core/facade/async'; import {Promise} from 'angular2/src/core/facade/async';
import {AppViewManager} from 'angular2/src/core/compiler/view_manager'; import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
import {ElementRef} from './element_ref'; import {ElementRef} from './element_ref';
import {ViewRef, HostViewRef} from './view_ref'; import {ViewRef, HostViewRef} from './view_ref';
function _asType(typeOrBinding: Type | Binding): Type {
return isType(typeOrBinding) ? typeOrBinding : (<Binding>typeOrBinding).token;
}
/** /**
* Angular's reference to a component instance. * Angular's reference to a component instance.
* *
@ -22,12 +26,20 @@ export class ComponentRef {
*/ */
instance: any; instance: any;
componentType: Type;
injector: Injector;
/** /**
* @private * @private
*/ */
constructor(location: ElementRef, instance: any, private _dispose: () => void) { constructor(location: ElementRef, instance: any, componentType: Type, injector: Injector,
private _dispose: () => void) {
this.location = location; this.location = location;
this.instance = instance; this.instance = instance;
this.componentType = componentType;
this.injector = injector;
} }
/** /**
@ -35,6 +47,10 @@ export class ComponentRef {
*/ */
get hostView(): HostViewRef { return this.location.parentView; } get hostView(): HostViewRef { return this.location.parentView; }
get hostComponentType(): Type { return this.componentType; }
get hostComponent(): any { return this.instance; }
/** /**
* Dispose of the component instance. * Dispose of the component instance.
*/ */
@ -104,8 +120,8 @@ export class DynamicComponentLoader {
* </my-app> * </my-app>
* ``` * ```
*/ */
loadAsRoot(typeOrBinding: Type | Binding, overrideSelector: string, loadAsRoot(typeOrBinding: Type | Binding, overrideSelector: string, injector: Injector,
injector: Injector): Promise<ComponentRef> { onDispose?: () => void): Promise<ComponentRef> {
return this._compiler.compileInHost(typeOrBinding) return this._compiler.compileInHost(typeOrBinding)
.then(hostProtoViewRef => { .then(hostProtoViewRef => {
var hostViewRef = var hostViewRef =
@ -113,8 +129,14 @@ export class DynamicComponentLoader {
var newLocation = this._viewManager.getHostElement(hostViewRef); var newLocation = this._viewManager.getHostElement(hostViewRef);
var component = this._viewManager.getComponent(newLocation); var component = this._viewManager.getComponent(newLocation);
var dispose = () => { this._viewManager.destroyRootHostView(hostViewRef); }; var dispose = () => {
return new ComponentRef(newLocation, component, dispose); this._viewManager.destroyRootHostView(hostViewRef);
if (isPresent(onDispose)) {
onDispose();
}
};
return new ComponentRef(newLocation, component, _asType(typeOrBinding), injector,
dispose);
}); });
} }
@ -229,7 +251,7 @@ export class DynamicComponentLoader {
viewContainer.remove(index); viewContainer.remove(index);
} }
}; };
return new ComponentRef(newLocation, component, dispose); return new ComponentRef(newLocation, component, _asType(typeOrBinding), null, dispose);
}); });
} }
} }

View File

@ -1,4 +1,4 @@
library testability.get_testability; library testability.browser_testability;
import './testability.dart'; import './testability.dart';
@ -80,8 +80,14 @@ class PublicTestability implements _JsObjectProxyable {
} }
} }
class GetTestability { class BrowserGetTestability implements GetTestability {
static addToWindow(TestabilityRegistry registry) { const BrowserGetTestability();
static init() {
setTestabilityGetter(const BrowserGetTestability());
}
void addToWindow(TestabilityRegistry registry) {
var jsRegistry = js.context['ngTestabilityRegistries']; var jsRegistry = js.context['ngTestabilityRegistries'];
if (jsRegistry == null) { if (jsRegistry == null) {
js.context['ngTestabilityRegistries'] = jsRegistry = new js.JsArray(); js.context['ngTestabilityRegistries'] = jsRegistry = new js.JsArray();
@ -106,10 +112,10 @@ class GetTestability {
return _jsify(result); return _jsify(result);
}); });
} }
jsRegistry.add(_createRegistry(registry)); jsRegistry.add(this._createRegistry(registry));
} }
static js.JsObject _createRegistry(TestabilityRegistry registry) { js.JsObject _createRegistry(TestabilityRegistry registry) {
var object = new js.JsObject(js.context['Object']); var object = new js.JsObject(js.context['Object']);
object['getAngularTestability'] = _jsify((Element elem, object['getAngularTestability'] = _jsify((Element elem,
bool findInAncestors) { bool findInAncestors) {

View File

@ -1,4 +1,9 @@
import {TestabilityRegistry, Testability} from 'angular2/src/core/testability/testability'; import {
TestabilityRegistry,
Testability,
GetTestability,
setTestabilityGetter
} from 'angular2/src/core/testability/testability';
import {global} from 'angular2/src/core/facade/lang'; import {global} from 'angular2/src/core/facade/lang';
class PublicTestability { class PublicTestability {
@ -13,8 +18,10 @@ class PublicTestability {
} }
} }
export class GetTestability { export class BrowserGetTestability implements GetTestability {
static addToWindow(registry: TestabilityRegistry) { static init() { setTestabilityGetter(new BrowserGetTestability()); }
addToWindow(registry: TestabilityRegistry): void {
global.getAngularTestability = function(elem: Element, findInAncestors: boolean = true): global.getAngularTestability = function(elem: Element, findInAncestors: boolean = true):
PublicTestability { PublicTestability {
var testability = registry.findTestabilityInTree(elem, findInAncestors); var testability = registry.findTestabilityInTree(elem, findInAncestors);

View File

@ -1,8 +1,8 @@
import {Injectable} from 'angular2/src/core/di'; import {Injectable} from 'angular2/src/core/di';
import {DOM} from 'angular2/src/core/dom/dom_adapter'; import {DOM} from 'angular2/src/core/dom/dom_adapter';
import {Map, MapWrapper, ListWrapper} from 'angular2/src/core/facade/collection'; import {Map, MapWrapper, ListWrapper} from 'angular2/src/core/facade/collection';
import {CONST, CONST_EXPR} from 'angular2/src/core/facade/lang';
import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions'; import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions';
import * as getTestabilityModule from './get_testability';
import {NgZone} from '../zone/ng_zone'; import {NgZone} from '../zone/ng_zone';
import {PromiseWrapper} from 'angular2/src/core/facade/async'; import {PromiseWrapper} from 'angular2/src/core/facade/async';
@ -76,7 +76,7 @@ export class Testability {
export class TestabilityRegistry { export class TestabilityRegistry {
_applications: Map<any, Testability> = new Map(); _applications: Map<any, Testability> = new Map();
constructor() { getTestabilityModule.GetTestability.addToWindow(this); } constructor() { testabilityGetter.addToWindow(this); }
registerApplication(token: any, testability: Testability) { registerApplication(token: any, testability: Testability) {
this._applications.set(token, testability); this._applications.set(token, testability);
@ -99,3 +99,16 @@ export class TestabilityRegistry {
return this.findTestabilityInTree(DOM.parentElement(elem)); return this.findTestabilityInTree(DOM.parentElement(elem));
} }
} }
export interface GetTestability { addToWindow(registry: TestabilityRegistry): void; }
@CONST()
class NoopGetTestability implements GetTestability {
addToWindow(registry: TestabilityRegistry): void {}
}
export function setTestabilityGetter(getter: GetTestability): void {
testabilityGetter = getter;
}
var testabilityGetter: GetTestability = CONST_EXPR(new NoopGetTestability());

View File

@ -7,7 +7,7 @@
import {createInjector} from "./di_bindings"; import {createInjector} from "./di_bindings";
import {MessageBus, MessageBusSink} from "angular2/src/web_workers/shared/message_bus"; import {MessageBus, MessageBusSink} from "angular2/src/web_workers/shared/message_bus";
import {createNgZone} from 'angular2/src/core/application_common'; import {createNgZone} from 'angular2/src/core/application_ref';
import {Injectable} from 'angular2/src/core/di'; import {Injectable} from 'angular2/src/core/di';
import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter'; import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter';
import {wtfInit} from 'angular2/src/core/profile/wtf_init'; import {wtfInit} from 'angular2/src/core/profile/wtf_init';

View File

@ -4,8 +4,8 @@ import "package:angular2/src/web_workers/shared/isolate_message_bus.dart";
import "package:angular2/src/web_workers/worker/application_common.dart" import "package:angular2/src/web_workers/worker/application_common.dart"
show bootstrapWebWorkerCommon; show bootstrapWebWorkerCommon;
import "package:angular2/src/core/facade/async.dart" show Future; import "package:angular2/src/core/facade/async.dart" show Future;
import "package:angular2/src/core/application_ref.dart" show ApplicationRef;
import "package:angular2/src/core/facade/lang.dart" show Type, BaseException; import "package:angular2/src/core/facade/lang.dart" show Type, BaseException;
import "package:angular2/src/core/compiler/dynamic_component_loader.dart" show ComponentRef;
import "dart:isolate"; import "dart:isolate";
import "dart:async"; import "dart:async";
import 'dart:core'; import 'dart:core';
@ -21,7 +21,7 @@ import 'dart:core';
* bootstrap() in a regular Angular application * bootstrap() in a regular Angular application
* See the bootstrap() docs for more details. * See the bootstrap() docs for more details.
*/ */
Future<ApplicationRef> bootstrapWebWorker( Future<ComponentRef> bootstrapWebWorker(
SendPort replyTo, Type appComponentType, SendPort replyTo, Type appComponentType,
[List<dynamic> componentInjectableBindings = null]) { [List<dynamic> componentInjectableBindings = null]) {
ReceivePort rPort = new ReceivePort(); ReceivePort rPort = new ReceivePort();

View File

@ -8,7 +8,7 @@ import {Binding, Injectable} from "angular2/src/core/di";
import {Map} from 'angular2/src/core/facade/collection'; import {Map} from 'angular2/src/core/facade/collection';
import {Promise} from 'angular2/src/core/facade/async'; import {Promise} from 'angular2/src/core/facade/async';
import {bootstrapWebWorkerCommon} from "angular2/src/web_workers/worker/application_common"; import {bootstrapWebWorkerCommon} from "angular2/src/web_workers/worker/application_common";
import {ApplicationRef} from "angular2/src/core/application_ref"; import {ComponentRef} from "angular2/src/core/compiler/dynamic_component_loader";
export * from "angular2/src/web_workers/shared/message_bus"; export * from "angular2/src/web_workers/shared/message_bus";
// TODO(jteplitz602) remove this and compile with lib.webworker.d.ts (#3492) // TODO(jteplitz602) remove this and compile with lib.webworker.d.ts (#3492)
@ -28,7 +28,7 @@ var _postMessage: PostMessageInterface = <any>postMessage;
*/ */
export function bootstrapWebWorker( export function bootstrapWebWorker(
appComponentType: Type, componentInjectableBindings: Array<Type | Binding | any[]> = null): appComponentType: Type, componentInjectableBindings: Array<Type | Binding | any[]> = null):
Promise<ApplicationRef> { Promise<ComponentRef> {
var sink = new PostMessageBusSink({ var sink = new PostMessageBusSink({
postMessage: (message: any, transferrables?:[ArrayBuffer]) => { postMessage: (message: any, transferrables?:[ArrayBuffer]) => {
console.log("Sending", message); console.log("Sending", message);

View File

@ -1,5 +1,4 @@
import {Injector, bind, OpaqueToken, Binding} from 'angular2/src/core/di'; import {Injector, bind, OpaqueToken, Binding} from 'angular2/src/core/di';
import {DEFAULT_PIPES} from 'angular2/src/core/pipes';
import {FORM_BINDINGS} from 'angular2/src/core/forms'; import {FORM_BINDINGS} from 'angular2/src/core/forms';
import { import {
NumberWrapper, NumberWrapper,
@ -10,50 +9,21 @@ import {
print, print,
stringify stringify
} from 'angular2/src/core/facade/lang'; } from 'angular2/src/core/facade/lang';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {Reflector, reflector} from 'angular2/src/core/reflection/reflection';
import {
Parser,
Lexer,
ChangeDetection,
DynamicChangeDetection,
JitChangeDetection,
PreGeneratedChangeDetection,
IterableDiffers,
defaultIterableDiffers,
KeyValueDiffers,
defaultKeyValueDiffers
} from 'angular2/src/core/change_detection/change_detection';
import {ExceptionHandler} from 'angular2/src/core/facade/exceptions'; import {ExceptionHandler} from 'angular2/src/core/facade/exceptions';
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
import {StyleUrlResolver} from 'angular2/src/core/render/dom/compiler/style_url_resolver';
import {PipeResolver} from 'angular2/src/core/compiler/pipe_resolver';
import {ViewResolver} from 'angular2/src/core/compiler/view_resolver';
import {ListWrapper} from 'angular2/src/core/facade/collection';
import {Promise, PromiseWrapper, PromiseCompleter} from 'angular2/src/core/facade/async'; import {Promise, PromiseWrapper, PromiseCompleter} from 'angular2/src/core/facade/async';
import {NgZone} from 'angular2/src/core/zone/ng_zone';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {XHR} from 'angular2/src/core/render/xhr'; import {XHR} from 'angular2/src/core/render/xhr';
import {WebWorkerXHRImpl} from 'angular2/src/web_workers/worker/xhr_impl'; import {WebWorkerXHRImpl} from 'angular2/src/web_workers/worker/xhr_impl';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
import {AppRootUrl} from 'angular2/src/core/services/app_root_url'; import {AppRootUrl} from 'angular2/src/core/services/app_root_url';
import {
ComponentRef,
DynamicComponentLoader
} from 'angular2/src/core/compiler/dynamic_component_loader';
import {AppViewPool, APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool';
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
import {WebWorkerRenderer, WebWorkerCompiler} from './renderer'; import {WebWorkerRenderer, WebWorkerCompiler} from './renderer';
import {Renderer, RenderCompiler} from 'angular2/src/core/render/api'; import {Renderer, RenderCompiler} from 'angular2/src/core/render/api';
import {internalView} from 'angular2/src/core/compiler/view_ref';
import {ClientMessageBrokerFactory} from 'angular2/src/web_workers/shared/client_message_broker'; import {ClientMessageBrokerFactory} from 'angular2/src/web_workers/shared/client_message_broker';
import {MessageBus} from 'angular2/src/web_workers/shared/message_bus'; import {MessageBus} from 'angular2/src/web_workers/shared/message_bus';
import {APP_COMPONENT_REF_PROMISE, APP_COMPONENT} from 'angular2/src/core/application_tokens'; import {
import {ApplicationRef} from 'angular2/src/core/application_ref'; platformCommon,
PlatformRef,
ApplicationRef,
applicationCommonBindings
} from 'angular2/src/core/application_ref';
import {Serializer} from "angular2/src/web_workers/shared/serializer"; import {Serializer} from "angular2/src/web_workers/shared/serializer";
import {ON_WEB_WORKER} from "angular2/src/web_workers/shared/api"; import {ON_WEB_WORKER} from "angular2/src/web_workers/shared/api";
import {RenderProtoViewRefStore} from 'angular2/src/web_workers/shared/render_proto_view_ref_store'; import {RenderProtoViewRefStore} from 'angular2/src/web_workers/shared/render_proto_view_ref_store';
@ -63,11 +33,12 @@ import {
import {ObservableWrapper} from 'angular2/src/core/facade/async'; import {ObservableWrapper} from 'angular2/src/core/facade/async';
import {SETUP_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api'; import {SETUP_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api';
import {WebWorkerEventDispatcher} from 'angular2/src/web_workers/worker/event_dispatcher'; import {WebWorkerEventDispatcher} from 'angular2/src/web_workers/worker/event_dispatcher';
import {ComponentRef} from 'angular2/src/core/compiler/dynamic_component_loader';
import {NgZone} from 'angular2/src/core/zone/ng_zone';
var _rootInjector: Injector; export function platform(bindings?: Array<Type | Binding | any[]>): PlatformRef {
return platformCommon(bindings);
// Contains everything that is safe to share between applications. }
var _rootBindings = [bind(Reflector).toValue(reflector)];
class PrintLogger { class PrintLogger {
log = print; log = print;
@ -76,29 +47,9 @@ class PrintLogger {
logGroupEnd() {} logGroupEnd() {}
} }
function _injectorBindings(appComponentType, bus: MessageBus, initData: StringMap<string, any>): function webWorkerBindings(appComponentType, bus: MessageBus, initData: StringMap<string, any>):
Array<Type | Binding | any[]> { Array<Type | Binding | any[]> {
var bestChangeDetection = new DynamicChangeDetection();
if (PreGeneratedChangeDetection.isSupported()) {
bestChangeDetection = new PreGeneratedChangeDetection();
} else if (JitChangeDetection.isSupported()) {
bestChangeDetection = new JitChangeDetection();
}
return [ return [
bind(APP_COMPONENT)
.toValue(appComponentType),
bind(APP_COMPONENT_REF_PROMISE)
.toFactory(
(dynamicComponentLoader, injector) => {
// TODO(rado): investigate whether to support bindings on root component.
return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector)
.then((componentRef) => { return componentRef; });
},
[DynamicComponentLoader, Injector]),
bind(appComponentType).toFactory((ref) => ref.instance, [APP_COMPONENT_REF_PROMISE]),
bind(LifeCycle).toFactory((exceptionHandler) => new LifeCycle(null, assertionsEnabled()),
[ExceptionHandler]),
Serializer, Serializer,
bind(MessageBus).toValue(bus), bind(MessageBus).toValue(bus),
ClientMessageBrokerFactory, ClientMessageBrokerFactory,
@ -109,93 +60,40 @@ function _injectorBindings(appComponentType, bus: MessageBus, initData: StringMa
bind(ON_WEB_WORKER).toValue(true), bind(ON_WEB_WORKER).toValue(true),
RenderViewWithFragmentsStore, RenderViewWithFragmentsStore,
RenderProtoViewRefStore, RenderProtoViewRefStore,
ProtoViewFactory,
AppViewPool,
bind(APP_VIEW_POOL_CAPACITY).toValue(10000),
AppViewManager,
AppViewManagerUtils,
AppViewListener,
Compiler,
CompilerCache,
ViewResolver,
DEFAULT_PIPES,
bind(IterableDiffers).toValue(defaultIterableDiffers),
bind(KeyValueDiffers).toValue(defaultKeyValueDiffers),
bind(ChangeDetection).toValue(bestChangeDetection),
DirectiveResolver,
UrlResolver,
StyleUrlResolver,
PipeResolver,
Parser,
Lexer,
bind(ExceptionHandler).toFactory(() => new ExceptionHandler(new PrintLogger()), []), bind(ExceptionHandler).toFactory(() => new ExceptionHandler(new PrintLogger()), []),
WebWorkerXHRImpl, WebWorkerXHRImpl,
bind(XHR).toAlias(WebWorkerXHRImpl), bind(XHR).toAlias(WebWorkerXHRImpl),
ComponentUrlMapper,
DynamicComponentLoader,
bind(AppRootUrl).toValue(new AppRootUrl(initData['rootUrl'])), bind(AppRootUrl).toValue(new AppRootUrl(initData['rootUrl'])),
WebWorkerEventDispatcher, WebWorkerEventDispatcher,
FORM_BINDINGS FORM_BINDINGS
]; ];
} }
export function bootstrapWebWorkerCommon( export function bootstrapWebWorkerCommon(appComponentType: Type, bus: MessageBus,
appComponentType: Type, bus: MessageBus, appBindings: Array<Type | Binding | any[]> = null):
componentInjectableBindings: Array<Type | Binding | any[]> = null): Promise<ApplicationRef> { Promise<ComponentRef> {
var bootstrapProcess: PromiseCompleter<any> = PromiseWrapper.completer(); var bootstrapProcess: PromiseCompleter<any> = PromiseWrapper.completer();
var appPromise = platform().asyncApplication((zone: NgZone) => {
var zone = new NgZone({enableLongStackTrace: assertionsEnabled()}); // TODO(rado): prepopulate template cache, so applications with only
// index.html and main.js are possible.
//
bus.attachToZone(zone); bus.attachToZone(zone);
bus.initChannel(SETUP_CHANNEL, false);
var subscription: any; var subscription: any;
bus.initChannel(SETUP_CHANNEL, false);
var emitter = bus.from(SETUP_CHANNEL); var emitter = bus.from(SETUP_CHANNEL);
subscription = ObservableWrapper.subscribe(emitter, (message: StringMap<string, any>) => { subscription = ObservableWrapper.subscribe(emitter, (message: StringMap<string, any>) => {
zone.run(() => { var bindings =
var exceptionHandler; [applicationCommonBindings(), webWorkerBindings(appComponentType, bus, message)];
try { if (isPresent(appBindings)) {
var appInjector = bindings.push(appBindings);
_createAppInjector(appComponentType, componentInjectableBindings, zone, bus, message); }
exceptionHandler = appInjector.get(ExceptionHandler); bootstrapProcess.resolve(bindings);
zone.overrideOnErrorHandler((e, s) => exceptionHandler.call(e, s));
var compRefToken: Promise<any> = appInjector.get(APP_COMPONENT_REF_PROMISE);
var tick = (componentRef) => {
var appChangeDetector = internalView(componentRef.hostView).changeDetector;
// retrieve life cycle: may have already been created if injected in root component
var lc = appInjector.get(LifeCycle);
lc.registerWith(zone, appChangeDetector);
lc.tick(); // the first tick that will bootstrap the app
bootstrapProcess.resolve(new ApplicationRef(componentRef, appComponentType, appInjector));
};
var tickResult = PromiseWrapper.then(compRefToken, tick);
PromiseWrapper.then(tickResult,
(_) => {}); // required for Dart to trigger the default error handler
PromiseWrapper.then(tickResult, null,
(err, stackTrace) => { bootstrapProcess.reject(err, stackTrace); });
ObservableWrapper.dispose(subscription); ObservableWrapper.dispose(subscription);
} catch (e) {
if (isPresent(exceptionHandler)) {
exceptionHandler.call(e, e.stack);
}
bootstrapProcess.reject(e, e.stack);
}
});
}); });
ObservableWrapper.callNext(bus.to(SETUP_CHANNEL), "ready"); ObservableWrapper.callNext(bus.to(SETUP_CHANNEL), "ready");
return bootstrapProcess.promise; return bootstrapProcess.promise;
} });
return PromiseWrapper.then(appPromise, (app) => app.bootstrap(appComponentType));
function _createAppInjector(appComponentType: Type, bindings: Array<Type | Binding | any[]>,
zone: NgZone, bus: MessageBus, initData: StringMap<string, any>):
Injector {
if (isBlank(_rootInjector)) _rootInjector = Injector.resolveAndCreate(_rootBindings);
var mergedBindings: any[] =
isPresent(bindings) ?
ListWrapper.concat(_injectorBindings(appComponentType, bus, initData), bindings) :
_injectorBindings(appComponentType, bus, initData);
mergedBindings.push(bind(NgZone).toValue(zone));
return _rootInjector.resolveAndCreateChild(mergedBindings);
} }

View File

@ -12,12 +12,12 @@ import {
} from 'angular2/test_lib'; } from 'angular2/test_lib';
import {isPresent, stringify} from 'angular2/src/core/facade/lang'; import {isPresent, stringify} from 'angular2/src/core/facade/lang';
import {bootstrap} from 'angular2/bootstrap'; import {bootstrap} from 'angular2/bootstrap';
import {Component, Directive, View} from 'angular2/src/core/metadata'; import {ApplicationRef} from 'angular2/src/core/application_ref';
import {Component, Directive, View} from 'angular2/core';
import {DOM} from 'angular2/src/core/dom/dom_adapter'; import {DOM} from 'angular2/src/core/dom/dom_adapter';
import {DOCUMENT} from 'angular2/render'; import {DOCUMENT} from 'angular2/render';
import {PromiseWrapper} from 'angular2/src/core/facade/async'; import {PromiseWrapper} from 'angular2/src/core/facade/async';
import {bind, Inject, Injector, LifeCycle} from 'angular2/core'; import {bind, Inject, Injector, LifeCycle} from 'angular2/core';
import {ApplicationRef} from 'angular2/src/core/application_ref';
import {ExceptionHandler} from 'angular2/src/core/facade/exceptions'; import {ExceptionHandler} from 'angular2/src/core/facade/exceptions';
import {Testability, TestabilityRegistry} from 'angular2/src/core/testability/testability'; import {Testability, TestabilityRegistry} from 'angular2/src/core/testability/testability';
import {IS_DART} from '../platform'; import {IS_DART} from '../platform';