66 * found in the LICENSE file at https://angular.io/license
77 */
88
9- import { APP_BASE_HREF , HashLocationStrategy , Location , LocationStrategy , PathLocationStrategy , PlatformLocation } from '@angular/common' ;
10- import { ANALYZE_FOR_ENTRY_COMPONENTS , APP_BOOTSTRAP_LISTENER , ApplicationRef , Compiler , ComponentRef , Inject , Injector , ModuleWithProviders , NgModule , NgModuleFactoryLoader , NgProbeToken , OpaqueToken , Optional , Provider , SkipSelf , SystemJsNgModuleLoader } from '@angular/core' ;
9+ import { APP_BASE_HREF , HashLocationStrategy , LOCATION_INITIALIZED , Location , LocationStrategy , PathLocationStrategy , PlatformLocation } from '@angular/common' ;
10+ import { ANALYZE_FOR_ENTRY_COMPONENTS , APP_BOOTSTRAP_LISTENER , APP_INITIALIZER , ApplicationRef , Compiler , ComponentRef , Inject , Injectable , Injector , ModuleWithProviders , NgModule , NgModuleFactoryLoader , NgProbeToken , OpaqueToken , Optional , Provider , SkipSelf , SystemJsNgModuleLoader } from '@angular/core' ;
11+ import { Subject } from 'rxjs/Subject' ;
12+ import { of } from 'rxjs/observable/of' ;
1113
1214import { Route , Routes } from './config' ;
1315import { RouterLink , RouterLinkWithHref } from './directives/router_link' ;
@@ -19,7 +21,7 @@ import {ErrorHandler, Router} from './router';
1921import { ROUTES } from './router_config_loader' ;
2022import { RouterOutletMap } from './router_outlet_map' ;
2123import { NoPreloading , PreloadAllModules , PreloadingStrategy , RouterPreloader } from './router_preloader' ;
22- import { ActivatedRoute } from './router_state' ;
24+ import { ActivatedRoute , RouterStateSnapshot } from './router_state' ;
2325import { UrlHandlingStrategy } from './url_handling_strategy' ;
2426import { DefaultUrlSerializer , UrlSerializer } from './url_tree' ;
2527import { flatten } from './utils/collection' ;
@@ -110,7 +112,7 @@ export function routerNgProbeToken() {
110112 * In addition, we often want to split applications into multiple bundles and load them on demand.
111113 * Doing this transparently is not trivial.
112114 *
113- * The Angular 2 router solves these problems. Using the router, you can declaratively specify
115+ * The Angular router solves these problems. Using the router, you can declaratively specify
114116 * application states, manage state transitions while taking care of the URL, and load bundles on
115117 * demand.
116118 *
@@ -278,22 +280,77 @@ export function rootRoute(router: Router): ActivatedRoute {
278280 return router . routerState . root ;
279281}
280282
281- export function initialRouterNavigation (
282- router : Router , ref : ApplicationRef , preloader : RouterPreloader , opts : ExtraOptions ) {
283- return ( bootstrappedComponentRef : ComponentRef < any > ) => {
283+ /**
284+ * To initialize the router properly we need to do in two steps:
285+ *
286+ * We need to start the navigation in a APP_INITIALIZER to block the bootstrap if
287+ * a resolver or a guards executes asynchronously. Second, we need to actually run
288+ * activation in a BOOTSTRAP_LISTENER. We utilize the afterPreactivation
289+ * hook provided by the router to do that.
290+ *
291+ * The router navigation starts, reaches the point when preactivation is done, and then
292+ * pauses. It waits for the hook to be resolved. We then resolve it only in a bootstrap listener.
293+ */
294+ @Injectable ( )
295+ export class RouterInitializer {
296+ private initNavigation : boolean ;
297+ private resultOfPreactivationDone = new Subject < void > ( ) ;
298+
299+ constructor ( private injector : Injector ) { }
300+
301+ appInitializer ( ) : Promise < any > {
302+ const p : Promise < any > = this . injector . get ( LOCATION_INITIALIZED , Promise . resolve ( null ) ) ;
303+ return p . then ( ( ) => {
304+ let resolve : Function = null ;
305+ const res = new Promise ( r => resolve = r ) ;
306+ const router = this . injector . get ( Router ) ;
307+ const opts = this . injector . get ( ROUTER_CONFIGURATION ) ;
308+
309+ if ( opts . initialNavigation === false ) {
310+ router . setUpLocationChangeListener ( ) ;
311+ } else {
312+ router . hooks . afterPreactivation = ( ) => {
313+ // only the initial navigation should be delayed
314+ if ( ! this . initNavigation ) {
315+ this . initNavigation = true ;
316+ resolve ( true ) ;
317+ return this . resultOfPreactivationDone ;
318+
319+ // subsequent navigations should not be delayed
320+ } else {
321+ return of ( null ) ;
322+ }
323+ } ;
324+ router . initialNavigation ( ) ;
325+ }
326+
327+ return res ;
328+ } ) ;
329+ }
284330
331+ bootstrapListener ( bootstrappedComponentRef : ComponentRef < any > ) : void {
332+ const ref = this . injector . get ( ApplicationRef ) ;
285333 if ( bootstrappedComponentRef !== ref . components [ 0 ] ) {
286334 return ;
287335 }
288336
289- router . resetRootComponentType ( ref . componentTypes [ 0 ] ) ;
337+ const preloader = this . injector . get ( RouterPreloader ) ;
290338 preloader . setUpPreloading ( ) ;
291- if ( opts . initialNavigation === false ) {
292- router . setUpLocationChangeListener ( ) ;
293- } else {
294- router . initialNavigation ( ) ;
295- }
296- } ;
339+
340+ const router = this . injector . get ( Router ) ;
341+ router . resetRootComponentType ( ref . componentTypes [ 0 ] ) ;
342+
343+ this . resultOfPreactivationDone . next ( null ) ;
344+ this . resultOfPreactivationDone . complete ( ) ;
345+ }
346+ }
347+
348+ export function getAppInitializer ( r : RouterInitializer ) {
349+ return r . appInitializer . bind ( r ) ;
350+ }
351+
352+ export function getBootstrapListener ( r : RouterInitializer ) {
353+ return r . bootstrapListener . bind ( r ) ;
297354}
298355
299356/**
@@ -305,11 +362,14 @@ export const ROUTER_INITIALIZER = new OpaqueToken('Router Initializer');
305362
306363export function provideRouterInitializer ( ) {
307364 return [
365+ RouterInitializer ,
308366 {
309- provide : ROUTER_INITIALIZER ,
310- useFactory : initialRouterNavigation ,
311- deps : [ Router , ApplicationRef , RouterPreloader , ROUTER_CONFIGURATION ]
367+ provide : APP_INITIALIZER ,
368+ multi : true ,
369+ useFactory : getAppInitializer ,
370+ deps : [ RouterInitializer ]
312371 } ,
372+ { provide : ROUTER_INITIALIZER , useFactory : getBootstrapListener , deps : [ RouterInitializer ] } ,
313373 { provide : APP_BOOTSTRAP_LISTENER , multi : true , useExisting : ROUTER_INITIALIZER } ,
314374 ] ;
315375}
0 commit comments