2016-06-23 09:47:54 -07:00
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
2017-02-03 05:42:22 -08:00
import { Observable } from 'rxjs/Observable' ;
import { Observer } from 'rxjs/Observer' ;
import { Subject } from 'rxjs/Subject' ;
import { Subscription } from 'rxjs/Subscription' ;
import { merge } from 'rxjs/observable/merge' ;
import { share } from 'rxjs/operator/share' ;
2016-08-25 00:50:16 -07:00
import { ErrorHandler } from '../src/error_handler' ;
2016-04-28 17:50:03 -07:00
import { ListWrapper } from '../src/facade/collection' ;
2017-02-03 05:42:22 -08:00
import { scheduleMicroTask , stringify } from '../src/facade/lang' ;
2016-09-18 15:55:08 -07:00
import { isPromise } from '../src/util/lang' ;
2016-06-08 16:38:52 -07:00
2016-08-02 07:54:14 -07:00
import { ApplicationInitStatus } from './application_init' ;
2016-08-02 07:38:14 -07:00
import { APP_BOOTSTRAP_LISTENER , PLATFORM_INITIALIZER } from './application_tokens' ;
2016-06-08 16:38:52 -07:00
import { Console } from './console' ;
2017-01-03 16:54:46 -08:00
import { Injectable , InjectionToken , Injector , Optional , Provider , ReflectiveInjector } from './di' ;
2016-08-11 15:24:35 -07:00
import { CompilerFactory , CompilerOptions } from './linker/compiler' ;
2016-06-08 16:38:52 -07:00
import { ComponentFactory , ComponentRef } from './linker/component_factory' ;
2016-06-30 13:07:17 -07:00
import { ComponentFactoryResolver } from './linker/component_factory_resolver' ;
2016-08-02 06:54:08 -07:00
import { NgModuleFactory , NgModuleInjector , NgModuleRef } from './linker/ng_module_factory' ;
2016-11-04 11:58:06 -07:00
import { AppView } from './linker/view' ;
import { ViewRef , ViewRef_ } from './linker/view_ref' ;
2016-06-08 16:38:52 -07:00
import { WtfScopeFn , wtfCreateScope , wtfLeave } from './profile/profile' ;
import { Testability , TestabilityRegistry } from './testability/testability' ;
2016-08-10 18:21:28 -07:00
import { Type } from './type' ;
2016-08-15 16:10:30 -07:00
import { NgZone } from './zone/ng_zone' ;
2016-06-08 16:38:52 -07:00
2016-09-20 14:14:57 -07:00
let _devMode : boolean = true ;
let _runModeLocked : boolean = false ;
let _platform : PlatformRef ;
2015-09-02 15:19:26 -07:00
2017-02-12 09:16:23 -08:00
export const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken < boolean >( 'AllowMultipleToken' );
2016-06-17 14:09:19 -07:00
/**
* Disable Angular's development mode, which turns off assertions and other
* checks within the framework.
*
* One important assertion this disables verifies that a change detection pass
* does not result in additional changes to any bindings (also known as
* unidirectional data flow).
2016-06-27 12:27:23 -07:00
*
2016-08-23 22:29:34 -07:00
* @stable
2016-06-17 14:09:19 -07:00
*/
export function enableProdMode () : void {
if ( _runModeLocked ) {
2016-08-25 00:50:16 -07:00
throw new Error ( 'Cannot enable prod mode after platform setup.' );
2016-06-17 14:09:19 -07:00
}
_devMode = false ;
}
/**
2016-07-07 14:42:46 -07:00
* Returns whether Angular is in development mode. After called once,
* the value is locked and won't change any more.
*
* By default, this is true, unless a user calls `enableProdMode` before calling this.
2016-06-27 12:27:23 -07:00
*
* @experimental APIs related to application bootstrap are currently under review.
2016-06-17 14:09:19 -07:00
*/
2016-07-07 14:42:46 -07:00
export function isDevMode () : boolean {
2016-06-17 14:09:19 -07:00
_runModeLocked = true ;
2016-07-07 14:42:46 -07:00
return _devMode ;
2016-06-17 14:09:19 -07:00
}
2016-11-09 14:58:40 -08:00
/**
* A token for third-party components that can register themselves with NgProbe.
*
* @experimental
*/
export class NgProbeToken {
constructor ( public name : string , public token : any ) {}
}
2015-11-13 11:21:16 -08:00
/**
2016-04-14 14:52:35 -07:00
* Creates a platform.
* Platforms have to be eagerly created via this function.
2016-06-27 12:27:23 -07:00
*
* @experimental APIs related to application bootstrap are currently under review.
2015-11-13 11:21:16 -08:00
*/
2016-04-14 14:52:35 -07:00
export function createPlatform ( injector : Injector ) : PlatformRef {
2017-02-12 09:16:23 -08:00
if ( _platform && ! _platform . destroyed &&
! _platform . injector . get ( ALLOW_MULTIPLE_PLATFORMS , false )) {
2016-08-25 00:50:16 -07:00
throw new Error (
2016-06-08 16:38:52 -07:00
'There can be only one platform. Destroy the previous one to create a new one.' );
2016-04-14 14:52:35 -07:00
}
2016-07-29 06:47:40 -07:00
_platform = injector . get ( PlatformRef );
2017-01-03 16:54:46 -08:00
const inits = injector . get ( PLATFORM_INITIALIZER , null );
2016-09-20 14:14:57 -07:00
if ( inits ) inits . forEach ( init => init ());
2016-04-14 14:52:35 -07:00
return _platform ;
}
2016-07-08 10:47:17 -07:00
/**
2016-08-08 17:18:50 -07:00
* Creates a factory for a platform
2016-07-08 10:47:17 -07:00
*
* @experimental APIs related to application bootstrap are currently under review.
*/
2016-07-18 03:50:31 -07:00
export function createPlatformFactory (
2016-12-17 02:21:58 +03:00
parentPlatformFactory : ( extraProviders? : Provider []) => PlatformRef , name : string ,
2016-08-30 18:07:40 -07:00
providers : Provider [] = []) : ( extraProviders? : Provider []) => PlatformRef {
2017-01-03 16:54:46 -08:00
const marker = new InjectionToken ( `Platform: ${ name } ` );
2016-08-24 13:39:44 -07:00
return ( extraProviders : Provider [] = []) => {
2017-02-12 09:16:23 -08:00
let platform = getPlatform ();
if ( ! platform || platform . injector . get ( ALLOW_MULTIPLE_PLATFORMS , false )) {
2016-12-17 02:21:58 +03:00
if ( parentPlatformFactory ) {
parentPlatformFactory (
2016-07-18 03:50:31 -07:00
providers . concat ( extraProviders ). concat ({ provide : marker , useValue : true }));
} else {
createPlatform ( ReflectiveInjector . resolveAndCreate (
providers . concat ( extraProviders ). concat ({ provide : marker , useValue : true })));
}
2016-07-08 10:47:17 -07:00
}
return assertPlatform ( marker );
};
}
2016-04-14 14:52:35 -07:00
/**
2017-02-12 09:16:23 -08:00
* Checks that there currently is a platform which contains the given token as a provider.
2016-06-27 12:27:23 -07:00
*
* @experimental APIs related to application bootstrap are currently under review.
2016-04-14 14:52:35 -07:00
*/
export function assertPlatform ( requiredToken : any ) : PlatformRef {
2016-09-20 14:14:57 -07:00
const platform = getPlatform ();
if ( ! platform ) {
2016-08-25 00:50:16 -07:00
throw new Error ( 'No platform exists!' );
2016-04-14 14:52:35 -07:00
}
2016-09-20 14:14:57 -07:00
if ( ! platform . injector . get ( requiredToken , null )) {
2016-08-25 00:50:16 -07:00
throw new Error (
2016-04-14 14:52:35 -07:00
'A platform with a different configuration has been created. Please destroy it first.' );
}
2016-09-20 14:14:57 -07:00
2016-04-14 14:52:35 -07:00
return platform ;
2015-11-13 11:21:16 -08:00
}
2015-11-12 13:40:29 -08:00
2016-08-02 02:32:27 -07:00
/**
* Destroy the existing platform.
*
* @experimental APIs related to application bootstrap are currently under review.
*/
export function destroyPlatform () : void {
2016-09-20 14:14:57 -07:00
if ( _platform && ! _platform . destroyed ) {
2016-08-02 02:32:27 -07:00
_platform . destroy ();
2015-11-18 09:18:37 -08:00
}
}
2016-04-14 14:52:35 -07:00
/**
* Returns the current platform.
2016-06-27 12:27:23 -07:00
*
* @experimental APIs related to application bootstrap are currently under review.
2016-04-14 14:52:35 -07:00
*/
export function getPlatform () : PlatformRef {
2016-09-20 14:14:57 -07:00
return _platform && ! _platform . destroyed ? _platform : null ;
2015-09-02 15:19:26 -07:00
}
/**
2015-09-15 15:51:15 -07:00
* 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
* to every Angular application running on the page are bound in its scope.
2015-08-20 17:18:27 -07:00
*
2015-09-15 15:51:15 -07:00
* A page's platform is initialized implicitly when {@link bootstrap}() is called, or
2016-04-14 14:52:35 -07:00
* explicitly by calling {@link createPlatform}().
2016-06-27 12:27:23 -07:00
*
2016-08-23 22:29:34 -07:00
* @stable
2015-08-20 17:18:27 -07:00
*/
2015-10-06 06:53:39 -07:00
export abstract class PlatformRef {
2015-10-26 10:50:25 -07:00
/**
2016-07-26 05:21:19 -07:00
* Creates an instance of an `@NgModule` for the given platform
* for offline compilation.
*
* ## Simple Example
*
* ```typescript
* my_module.ts:
*
* @NgModule({
* imports: [BrowserModule]
* })
* class MyModule {}
*
* main.ts:
* import {MyModuleNgFactory} from './my_module.ngfactory';
2016-08-15 13:44:01 -07:00
* import {platformBrowser} from '@angular/platform-browser';
2016-07-26 05:21:19 -07:00
*
2016-08-15 13:44:01 -07:00
* let moduleRef = platformBrowser().bootstrapModuleFactory(MyModuleNgFactory);
2016-07-26 05:21:19 -07:00
* ```
*
* @experimental APIs related to application bootstrap are currently under review.
*/
2017-01-25 22:32:32 -08:00
abstract bootstrapModuleFactory < M >( moduleFactory : NgModuleFactory < M >) : Promise < NgModuleRef < M >>;
2016-07-26 05:21:19 -07:00
/**
* Creates an instance of an `@NgModule` for a given platform using the given runtime compiler.
*
* ## Simple Example
*
* ```typescript
* @NgModule({
* imports: [BrowserModule]
* })
* class MyModule {}
*
2016-08-15 13:44:01 -07:00
* let moduleRef = platformBrowser().bootstrapModule(MyModule);
2016-07-26 05:21:19 -07:00
* ```
* @stable
2015-10-26 10:50:25 -07:00
*/
2017-01-25 22:36:38 -08:00
abstract bootstrapModule < M >(
moduleType : Type < M >,
compilerOptions? : CompilerOptions | CompilerOptions []) : Promise < NgModuleRef < M >>;
2016-07-26 05:21:19 -07:00
2016-08-02 02:32:27 -07:00
/**
* Register a listener to be called when the platform is disposed.
*/
abstract onDestroy ( callback : () => void ) : void ;
2015-09-02 15:19:26 -07:00
/**
2015-09-15 15:51:15 -07:00
* Retrieve the platform {@link Injector}, which is the parent injector for
2015-10-10 22:11:13 -07:00
* every Angular application on the page and provides singleton providers.
2015-09-02 15:19:26 -07:00
*/
2017-01-25 22:32:32 -08:00
abstract get injector () : Injector ;
2015-08-20 17:18:27 -07:00
2016-08-02 02:32:27 -07:00
/**
* Destroy the Angular platform and all Angular applications on the page.
*/
abstract destroy () : void ;
2017-01-25 22:32:32 -08:00
abstract get destroyed () : boolean ;
2015-10-06 06:53:39 -07:00
}
2016-08-30 18:07:40 -07:00
function _callAndReportToErrorHandler ( errorHandler : ErrorHandler , callback : () => any ) : any {
2016-07-29 06:47:40 -07:00
try {
const result = callback ();
if ( isPromise ( result )) {
return result . catch (( e : any ) => {
2016-08-25 00:50:16 -07:00
errorHandler . handleError ( e );
2016-07-29 06:47:40 -07:00
// rethrow as the exception handler might not do it
throw e ;
});
}
2016-09-20 14:14:57 -07:00
return result ;
2016-07-29 06:47:40 -07:00
} catch ( e ) {
2016-08-25 00:50:16 -07:00
errorHandler . handleError ( e );
2016-07-29 06:47:40 -07:00
// rethrow as the exception handler might not do it
throw e ;
}
}
2017-01-30 16:25:15 -08:00
/**
* workaround https://github.com/angular/tsickle/issues/350
* @suppress {checkTypes}
*/
2016-04-14 14:52:35 -07:00
@Injectable ()
2015-10-06 06:53:39 -07:00
export class PlatformRef_ extends PlatformRef {
2016-08-02 02:32:27 -07:00
private _modules : NgModuleRef < any >[] = [];
private _destroyListeners : Function [] = [];
private _destroyed : boolean = false ;
2015-10-06 06:53:39 -07:00
2016-07-29 06:47:40 -07:00
constructor ( private _injector : Injector ) { super (); }
2015-10-06 06:53:39 -07:00
2016-08-02 02:32:27 -07:00
onDestroy ( callback : () => void ) : void { this . _destroyListeners . push ( callback ); }
2015-09-02 15:19:26 -07:00
2016-04-14 14:52:35 -07:00
get injector () : Injector { return this . _injector ; }
2015-09-02 15:19:26 -07:00
2016-08-02 02:32:27 -07:00
get destroyed() { return this . _destroyed ; }
2016-04-14 14:52:35 -07:00
2016-08-02 02:32:27 -07:00
destroy() {
if ( this . _destroyed ) {
2016-08-25 00:50:16 -07:00
throw new Error ( 'The platform has already been destroyed!' );
2016-08-02 02:32:27 -07:00
}
2016-09-20 14:14:57 -07:00
this . _modules . slice (). forEach ( module => module . destroy ());
this . _destroyListeners . forEach ( listener => listener ());
2016-08-02 02:32:27 -07:00
this . _destroyed = true ;
2015-09-02 15:19:26 -07:00
}
2016-07-29 06:47:40 -07:00
bootstrapModuleFactory < M >( moduleFactory : NgModuleFactory < M >) : Promise < NgModuleRef < M >> {
2016-08-05 13:32:04 -07:00
return this . _bootstrapModuleFactoryWithZone ( moduleFactory , null );
}
private _bootstrapModuleFactoryWithZone < M >( moduleFactory : NgModuleFactory < M >, ngZone : NgZone ) :
Promise < NgModuleRef < M >> {
2016-07-26 05:21:19 -07:00
// Note: We need to create the NgZone _before_ we instantiate the module,
// as instantiating the module creates some providers eagerly.
// So we create a mini parent injector that just contains the new NgZone and
// pass that as parent to the NgModuleFactory.
2016-08-05 13:32:04 -07:00
if ( ! ngZone ) ngZone = new NgZone ({ enableLongStackTrace : isDevMode ()});
2016-07-29 06:47:40 -07:00
// Attention: Don't use ApplicationRef.run here,
// as we want to be sure that all possible constructor calls are inside `ngZone.run`!
return ngZone . run (() => {
const ngZoneInjector =
ReflectiveInjector . resolveAndCreate ([{ provide : NgZone , useValue : ngZone }], this . injector );
2016-08-02 06:54:08 -07:00
const moduleRef = < NgModuleInjector < M >> moduleFactory . create ( ngZoneInjector );
2016-08-25 00:50:16 -07:00
const exceptionHandler : ErrorHandler = moduleRef . injector . get ( ErrorHandler , null );
2016-07-29 14:45:05 -07:00
if ( ! exceptionHandler ) {
2016-08-30 18:07:40 -07:00
throw new Error ( 'No ErrorHandler. Is platform module (BrowserModule) included?' );
2016-07-29 14:45:05 -07:00
}
2016-08-02 02:32:27 -07:00
moduleRef . onDestroy (() => ListWrapper . remove ( this . _modules , moduleRef ));
2016-08-25 00:50:16 -07:00
ngZone . onError . subscribe ({ next : ( error : any ) => { exceptionHandler . handleError ( error ); }});
2016-08-30 18:07:40 -07:00
return _callAndReportToErrorHandler ( exceptionHandler , () => {
2016-08-02 07:54:14 -07:00
const initStatus : ApplicationInitStatus = moduleRef . injector . get ( ApplicationInitStatus );
2016-08-02 07:38:14 -07:00
return initStatus . donePromise . then (() => {
2016-08-02 06:54:08 -07:00
this . _moduleDoBootstrap ( moduleRef );
2016-07-29 06:47:40 -07:00
return moduleRef ;
});
});
});
2016-07-26 05:21:19 -07:00
}
2016-08-10 18:21:28 -07:00
bootstrapModule < M >( moduleType : Type < M >, compilerOptions : CompilerOptions | CompilerOptions [] = []) :
Promise < NgModuleRef < M >> {
2016-08-05 13:32:04 -07:00
return this . _bootstrapModuleWithZone ( moduleType , compilerOptions , null );
}
private _bootstrapModuleWithZone < M >(
2017-01-19 13:04:24 +02:00
moduleType : Type < M >, compilerOptions : CompilerOptions | CompilerOptions [] = [],
2017-02-01 11:46:57 -08:00
ngZone : NgZone = null ) : Promise < NgModuleRef < M >> {
2016-07-26 05:21:19 -07:00
const compilerFactory : CompilerFactory = this . injector . get ( CompilerFactory );
const compiler = compilerFactory . createCompiler (
2016-09-20 14:14:57 -07:00
Array . isArray ( compilerOptions ) ? compilerOptions : [ compilerOptions ]);
2016-08-19 13:51:45 -07:00
2016-07-26 05:21:19 -07:00
return compiler . compileModuleAsync ( moduleType )
2016-08-05 13:32:04 -07:00
. then (( moduleFactory ) => this . _bootstrapModuleFactoryWithZone ( moduleFactory , ngZone ));
2016-07-26 05:21:19 -07:00
}
2016-08-02 06:54:08 -07:00
2017-01-01 20:46:53 +03:00
private _moduleDoBootstrap ( moduleRef : NgModuleInjector < any >) : void {
2016-08-02 06:54:08 -07:00
const appRef = moduleRef . injector . get ( ApplicationRef );
if ( moduleRef . bootstrapFactories . length > 0 ) {
moduleRef . bootstrapFactories . forEach (( compFactory ) => appRef . bootstrap ( compFactory ));
} else if ( moduleRef . instance . ngDoBootstrap ) {
moduleRef . instance . ngDoBootstrap ( appRef );
} else {
2016-08-25 00:50:16 -07:00
throw new Error (
2016-08-02 06:54:08 -07:00
`The module ${ stringify ( moduleRef . instance . constructor ) } was bootstrapped, but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. ` +
`Please define one of these.` );
}
2017-01-01 20:46:53 +03:00
this . _modules . push ( moduleRef );
2016-08-02 06:54:08 -07:00
}
2015-09-02 15:19:26 -07:00
}
/**
2015-09-15 15:51:15 -07:00
* A reference to an Angular application running on a page.
2015-09-02 15:19:26 -07:00
*
2015-09-15 15:51:15 -07:00
* For more about Angular applications, see the documentation for {@link bootstrap}.
2016-06-27 12:27:23 -07:00
*
2016-08-23 22:29:34 -07:00
* @stable
2015-09-02 15:19:26 -07:00
*/
2015-10-06 06:53:39 -07:00
export abstract class ApplicationRef {
2015-08-20 17:18:27 -07:00
/**
2015-09-15 15:51:15 -07:00
* Bootstrap a new component at the root level of the application.
*
2015-11-17 09:41:31 -08:00
* ### Bootstrap process
2015-09-15 15:51:15 -07:00
*
* When bootstrapping a new root component into an application, Angular mounts the
* specified application component onto DOM elements identified by the [componentType]'s
* selector and kicks off automatic change detection to finish initializing the component.
*
2015-10-19 15:37:32 +01:00
* ### Example
2015-11-30 08:28:54 -08:00
* {@example core/ts/platform/platform.ts region='longform'}
2015-09-02 15:19:26 -07:00
*/
2016-08-10 18:21:28 -07:00
abstract bootstrap < C >( componentFactory : ComponentFactory < C > | Type < C >) : ComponentRef < C >;
2015-10-06 06:53:39 -07:00
2015-10-28 10:34:13 -07:00
/**
* Invoke this method to explicitly process change detection and its side-effects.
*
* In development mode, `tick()` also performs a second change detection cycle to ensure that no
* further changes are detected. If additional changes are picked up during this second cycle,
* bindings in the app have side-effects that cannot be resolved in a single change detection
* pass.
* In this case, Angular throws an error, since an Angular application can only have one change
* detection pass during which all change detection must complete.
*/
abstract tick () : void ;
2015-10-09 16:22:07 -07:00
/**
* Get a list of component types registered to this application.
2016-08-02 07:49:33 -07:00
* This list is populated even before the component is created.
2015-10-09 16:22:07 -07:00
*/
2017-01-25 22:32:32 -08:00
abstract get componentTypes () : Type < any >[];
2016-08-02 07:49:33 -07:00
2016-08-02 06:54:08 -07:00
/**
* Get a list of components registered to this application.
*/
2017-01-25 22:32:32 -08:00
abstract get components () : ComponentRef < any >[];
2016-11-04 11:58:06 -07:00
/**
* Attaches a view so that it will be dirty checked.
* The view will be automatically detached when it is destroyed.
* This will throw if the view is already attached to a ViewContainer.
*/
2017-01-25 22:32:32 -08:00
abstract attachView ( view : ViewRef ) : void ;
2016-11-04 11:58:06 -07:00
/**
* Detaches a view from dirty checking again.
*/
2017-01-25 22:32:32 -08:00
abstract detachView ( view : ViewRef ) : void ;
2016-11-04 11:58:06 -07:00
/**
* Returns the number of attached views.
*/
2017-01-25 22:32:32 -08:00
abstract get viewCount () : number ;
2017-02-03 05:42:22 -08:00
/**
* Returns an Observable that indicates when the application is stable or unstable.
*/
abstract get isStable () : Observable < boolean >;
2015-10-06 06:53:39 -07:00
}
2017-01-30 16:25:15 -08:00
/**
* workaround https://github.com/angular/tsickle/issues/350
* @suppress {checkTypes}
*/
2016-04-14 14:52:35 -07:00
@Injectable ()
2015-10-06 06:53:39 -07:00
export class ApplicationRef_ extends ApplicationRef {
2015-10-28 10:34:13 -07:00
/** @internal */
static _tickScope : WtfScopeFn = wtfCreateScope ( 'ApplicationRef#tick()' );
2017-01-03 16:54:46 -08:00
private _bootstrapListeners : (( compRef : ComponentRef < any >) => void )[] = [];
2016-04-30 10:52:04 -07:00
private _rootComponents : ComponentRef < any >[] = [];
2016-08-10 18:21:28 -07:00
private _rootComponentTypes : Type < any >[] = [];
2016-11-04 11:58:06 -07:00
private _views : AppView < any >[] = [];
2015-10-28 10:34:13 -07:00
private _runningTick : boolean = false ;
private _enforceNoNewChanges : boolean = false ;
2017-02-03 05:42:22 -08:00
private _isStable : Observable < boolean >;
private _stable = true ;
2015-10-06 06:53:39 -07:00
2016-06-30 13:07:17 -07:00
constructor (
2016-08-02 02:32:27 -07:00
private _zone : NgZone , private _console : Console , private _injector : Injector ,
2016-08-25 00:50:16 -07:00
private _exceptionHandler : ErrorHandler ,
2016-06-30 13:07:17 -07:00
private _componentFactoryResolver : ComponentFactoryResolver ,
2016-08-02 07:54:14 -07:00
private _initStatus : ApplicationInitStatus ,
2016-06-30 13:07:17 -07:00
@Optional () private _testabilityRegistry : TestabilityRegistry ,
2016-07-29 06:47:40 -07:00
@Optional () private _testability : Testability ) {
2015-10-06 06:53:39 -07:00
super ();
2016-06-17 14:09:19 -07:00
this . _enforceNoNewChanges = isDevMode ();
2016-08-02 15:53:34 -07:00
this . _zone . onMicrotaskEmpty . subscribe (
{ next : () => { this . _zone . run (() => { this . tick (); }); }});
2017-02-03 05:42:22 -08:00
const isCurrentlyStable = new Observable < boolean >(( observer : Observer < boolean >) => {
this . _stable = this . _zone . isStable && ! this . _zone . hasPendingMacrotasks &&
! this . _zone . hasPendingMicrotasks ;
this . _zone . runOutsideAngular (() => {
observer . next ( this . _stable );
observer . complete ();
});
});
const isStable = new Observable < boolean >(( observer : Observer < boolean >) => {
const stableSub : Subscription = this . _zone . onStable . subscribe (() => {
NgZone . assertNotInAngularZone ();
// Check whether there are no pending macro/micro tasks in the next tick
// to allow for NgZone to update the state.
scheduleMicroTask (() => {
if ( ! this . _stable && ! this . _zone . hasPendingMacrotasks &&
! this . _zone . hasPendingMicrotasks ) {
this . _stable = true ;
observer . next ( true );
}
});
});
const unstableSub : Subscription = this . _zone . onUnstable . subscribe (() => {
NgZone . assertInAngularZone ();
if ( this . _stable ) {
this . _stable = false ;
this . _zone . runOutsideAngular (() => { observer . next ( false ); });
}
});
return () => {
stableSub . unsubscribe ();
unstableSub . unsubscribe ();
};
});
this . _isStable = merge ( isCurrentlyStable , share . call ( isStable ));
2015-10-06 06:53:39 -07:00
}
2016-11-04 11:58:06 -07:00
attachView ( viewRef : ViewRef ) : void {
const view = ( viewRef as ViewRef_ < any >). internalView ;
this . _views . push ( view );
view . attachToAppRef ( this );
2015-10-28 10:34:13 -07:00
}
2016-11-04 11:58:06 -07:00
detachView ( viewRef : ViewRef ) : void {
const view = ( viewRef as ViewRef_ < any >). internalView ;
ListWrapper . remove ( this . _views , view );
view . detach ();
2015-11-10 10:40:33 -08:00
}
2016-08-10 18:21:28 -07:00
bootstrap < C >( componentOrFactory : ComponentFactory < C > | Type < C >) : ComponentRef < C > {
2016-08-02 07:38:14 -07:00
if ( ! this . _initStatus . done ) {
2016-08-25 00:50:16 -07:00
throw new Error (
2016-08-02 07:38:14 -07:00
'Cannot bootstrap as there are still asynchronous initializers running. Bootstrap components in the `ngDoBootstrap` method of the root module.' );
}
2016-08-02 07:48:15 -07:00
let componentFactory : ComponentFactory < C >;
if ( componentOrFactory instanceof ComponentFactory ) {
componentFactory = componentOrFactory ;
} else {
componentFactory = this . _componentFactoryResolver . resolveComponentFactory ( componentOrFactory );
}
this . _rootComponentTypes . push ( componentFactory . componentType );
2016-09-20 14:14:57 -07:00
const compRef = componentFactory . create ( this . _injector , [], componentFactory . selector );
2016-08-02 07:48:15 -07:00
compRef . onDestroy (() => { this . _unloadComponent ( compRef ); });
2016-09-20 14:14:57 -07:00
const testability = compRef . injector . get ( Testability , null );
if ( testability ) {
2016-08-02 07:48:15 -07:00
compRef . injector . get ( TestabilityRegistry )
. registerApplication ( compRef . location . nativeElement , testability );
}
2016-04-14 14:52:35 -07:00
2016-08-02 07:48:15 -07:00
this . _loadComponent ( compRef );
if ( isDevMode ()) {
this . _console . log (
2017-01-03 19:03:58 +01:00
`Angular is running in the development mode. Call enableProdMode() to enable the production mode.` );
2016-08-02 07:48:15 -07:00
}
return compRef ;
2015-09-02 15:19:26 -07:00
}
2016-11-04 11:58:06 -07:00
private _loadComponent ( componentRef : ComponentRef < any >) : void {
this . attachView ( componentRef . hostView );
2015-11-10 10:40:33 -08:00
this . tick ();
2016-02-11 17:01:17 -08:00
this . _rootComponents . push ( componentRef );
2016-08-02 05:22:44 -07:00
// Get the listeners lazily to prevent DI cycles.
const listeners =
2017-01-03 16:54:46 -08:00
this . _injector . get ( APP_BOOTSTRAP_LISTENER , []). concat ( this . _bootstrapListeners );
2016-08-02 05:22:44 -07:00
listeners . forEach (( listener ) => listener ( componentRef ));
2015-11-10 10:40:33 -08:00
}
2016-11-04 11:58:06 -07:00
private _unloadComponent ( componentRef : ComponentRef < any >) : void {
this . detachView ( componentRef . hostView );
2016-02-11 17:01:17 -08:00
ListWrapper . remove ( this . _rootComponents , componentRef );
2015-11-10 10:40:33 -08:00
}
2015-10-28 10:34:13 -07:00
tick () : void {
if ( this . _runningTick ) {
2016-08-25 00:50:16 -07:00
throw new Error ( 'ApplicationRef.tick is called recursively' );
2015-10-28 10:34:13 -07:00
}
2016-09-20 14:14:57 -07:00
const scope = ApplicationRef_ . _tickScope ();
2015-10-28 10:34:13 -07:00
try {
this . _runningTick = true ;
2016-11-04 11:58:06 -07:00
this . _views . forEach (( view ) => view . ref . detectChanges ());
2015-10-28 10:34:13 -07:00
if ( this . _enforceNoNewChanges ) {
2016-11-04 11:58:06 -07:00
this . _views . forEach (( view ) => view . ref . checkNoChanges ());
2015-10-28 10:34:13 -07:00
}
} finally {
this . _runningTick = false ;
2016-09-20 14:14:57 -07:00
wtfLeave ( scope );
2015-10-28 10:34:13 -07:00
}
}
2016-08-02 02:32:27 -07:00
ngOnDestroy() {
2015-09-02 15:19:26 -07:00
// TODO(alxhub): Dispose of the NgZone.
2016-11-04 11:58:06 -07:00
this . _views . slice (). forEach (( view ) => view . destroy ());
2015-09-02 15:19:26 -07:00
}
2015-10-09 16:22:07 -07:00
2016-11-04 11:58:06 -07:00
get viewCount() { return this . _views . length ; }
2016-08-10 18:21:28 -07:00
get componentTypes () : Type < any >[] { return this . _rootComponentTypes ; }
2016-08-02 06:54:08 -07:00
get components () : ComponentRef < any >[] { return this . _rootComponents ; }
2017-02-03 05:42:22 -08:00
get isStable () : Observable < boolean > { return this . _isStable ; }
2015-08-20 17:18:27 -07:00
}