2016-07-06 18:36:50 -04: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
|
|
|
|
*/
|
|
|
|
|
2016-07-28 15:10:36 -04:00
|
|
|
import {APP_BASE_HREF, HashLocationStrategy, Location, LocationStrategy, PathLocationStrategy, PlatformLocation} from '@angular/common';
|
2016-08-25 03:50:16 -04:00
|
|
|
import {ANALYZE_FOR_ENTRY_COMPONENTS, APP_BOOTSTRAP_LISTENER, ApplicationRef, Compiler, Inject, Injector, ModuleWithProviders, NgModule, NgModuleFactoryLoader, OpaqueToken, Optional, Provider, SkipSelf, SystemJsNgModuleLoader} from '@angular/core';
|
2016-07-06 18:36:50 -04:00
|
|
|
|
2016-08-16 16:40:28 -04:00
|
|
|
import {Route, Routes} from './config';
|
2016-07-06 19:19:52 -04:00
|
|
|
import {RouterLink, RouterLinkWithHref} from './directives/router_link';
|
|
|
|
import {RouterLinkActive} from './directives/router_link_active';
|
|
|
|
import {RouterOutlet} from './directives/router_outlet';
|
2016-08-25 10:56:30 -04:00
|
|
|
import {ErrorHandler, Router} from './router';
|
2016-07-06 19:19:52 -04:00
|
|
|
import {ROUTES} from './router_config_loader';
|
2016-07-06 18:36:50 -04:00
|
|
|
import {RouterOutletMap} from './router_outlet_map';
|
2016-09-16 18:08:15 -04:00
|
|
|
import {NoPreloading, PreloadAllModules, PreloadingStrategy, RouterPreloader} from './router_preloader';
|
2016-07-06 18:36:50 -04:00
|
|
|
import {ActivatedRoute} from './router_state';
|
2016-10-20 13:44:44 -04:00
|
|
|
import {UrlHandlingStrategy} from './url_handling_strategy';
|
2016-07-06 18:36:50 -04:00
|
|
|
import {DefaultUrlSerializer, UrlSerializer} from './url_tree';
|
2016-08-16 16:40:28 -04:00
|
|
|
import {flatten} from './utils/collection';
|
2016-07-06 18:36:50 -04:00
|
|
|
|
|
|
|
|
2016-07-25 19:10:10 -04:00
|
|
|
|
2016-07-06 18:36:50 -04:00
|
|
|
/**
|
2016-09-10 19:53:27 -04:00
|
|
|
* @whatItDoes Contains a list of directives
|
2016-07-06 18:36:50 -04:00
|
|
|
* @stable
|
|
|
|
*/
|
2016-08-26 12:33:37 -04:00
|
|
|
const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkWithHref, RouterLinkActive];
|
2016-07-06 18:36:50 -04:00
|
|
|
|
2016-08-16 16:40:28 -04:00
|
|
|
/**
|
2016-09-12 12:47:44 -04:00
|
|
|
* @whatItDoes Is used in DI to configure the router.
|
2016-08-16 16:40:28 -04:00
|
|
|
* @stable
|
|
|
|
*/
|
|
|
|
export const ROUTER_CONFIGURATION = new OpaqueToken('ROUTER_CONFIGURATION');
|
|
|
|
|
2016-09-10 19:53:27 -04:00
|
|
|
/**
|
|
|
|
* @docsNotRequired
|
|
|
|
*/
|
2016-08-23 14:57:58 -04:00
|
|
|
export const ROUTER_FORROOT_GUARD = new OpaqueToken('ROUTER_FORROOT_GUARD');
|
|
|
|
|
2016-07-27 12:54:19 -04:00
|
|
|
const pathLocationStrategy = {
|
|
|
|
provide: LocationStrategy,
|
|
|
|
useClass: PathLocationStrategy
|
|
|
|
};
|
|
|
|
const hashLocationStrategy = {
|
|
|
|
provide: LocationStrategy,
|
|
|
|
useClass: HashLocationStrategy
|
|
|
|
};
|
|
|
|
|
2016-08-24 16:39:44 -04:00
|
|
|
export const ROUTER_PROVIDERS: Provider[] = [
|
2016-07-27 12:54:19 -04:00
|
|
|
Location, {provide: UrlSerializer, useClass: DefaultUrlSerializer}, {
|
2016-07-07 17:13:32 -04:00
|
|
|
provide: Router,
|
|
|
|
useFactory: setupRouter,
|
|
|
|
deps: [
|
2016-08-16 16:40:28 -04:00
|
|
|
ApplicationRef, UrlSerializer, RouterOutletMap, Location, Injector, NgModuleFactoryLoader,
|
2016-10-20 13:44:44 -04:00
|
|
|
Compiler, ROUTES, ROUTER_CONFIGURATION, [UrlHandlingStrategy, new Optional()]
|
2016-07-07 17:13:32 -04:00
|
|
|
]
|
|
|
|
},
|
2016-07-25 19:10:10 -04:00
|
|
|
RouterOutletMap, {provide: ActivatedRoute, useFactory: rootRoute, deps: [Router]},
|
2016-09-16 18:08:15 -04:00
|
|
|
{provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader}, RouterPreloader, NoPreloading,
|
|
|
|
PreloadAllModules, {provide: ROUTER_CONFIGURATION, useValue: {enableTracing: false}}
|
2016-07-07 17:13:32 -04:00
|
|
|
];
|
2016-07-06 18:36:50 -04:00
|
|
|
|
2016-07-18 06:50:31 -04:00
|
|
|
/**
|
2016-09-10 19:53:27 -04:00
|
|
|
* @whatItDoes Adds router directives and providers.
|
|
|
|
*
|
|
|
|
* @howToUse
|
2016-07-27 12:54:19 -04:00
|
|
|
*
|
2016-09-10 19:53:27 -04:00
|
|
|
* RouterModule can be imported multiple times: once per lazily-loaded bundle.
|
|
|
|
* Since the router deals with a global shared resource--location, we cannot have
|
|
|
|
* more than one router service active.
|
2016-07-18 06:50:31 -04:00
|
|
|
*
|
2016-09-10 19:53:27 -04:00
|
|
|
* That is why there are two ways to create the module: `RouterModule.forRoot` and
|
|
|
|
* `RouterModule.forChild`.
|
|
|
|
*
|
|
|
|
* * `forRoot` creates a module that contains all the directives, the given routes, and the router
|
|
|
|
* service itself.
|
|
|
|
* * `forChild` creates a module that contains all the directives and the given routes, but does not
|
|
|
|
* include
|
|
|
|
* the router service.
|
|
|
|
*
|
|
|
|
* When registered at the root, the module should be used as follows
|
2016-07-18 06:50:31 -04:00
|
|
|
*
|
|
|
|
* ```
|
2016-09-10 19:53:27 -04:00
|
|
|
* @NgModule({
|
|
|
|
* imports: [RouterModule.forRoot(ROUTES)]
|
|
|
|
* })
|
|
|
|
* class MyNgModule {}
|
2016-07-18 06:50:31 -04:00
|
|
|
* ```
|
|
|
|
*
|
2016-09-10 19:53:27 -04:00
|
|
|
* For submodules and lazy loaded submodules the module should be used as follows:
|
2016-07-06 18:36:50 -04:00
|
|
|
*
|
|
|
|
* ```
|
2016-07-27 12:54:19 -04:00
|
|
|
* @NgModule({
|
2016-09-10 19:53:27 -04:00
|
|
|
* imports: [RouterModule.forChild(ROUTES)]
|
2016-07-27 12:54:19 -04:00
|
|
|
* })
|
2016-09-10 19:53:27 -04:00
|
|
|
* class MyNgModule {}
|
2016-07-06 18:36:50 -04:00
|
|
|
* ```
|
|
|
|
*
|
2016-09-10 19:53:27 -04:00
|
|
|
* @description
|
|
|
|
*
|
|
|
|
* Managing state transitions is one of the hardest parts of building applications. This is
|
|
|
|
* especially true on the web, where you also need to ensure that the state is reflected in the URL.
|
|
|
|
* In addition, we often want to split applications into multiple bundles and load them on demand.
|
|
|
|
* Doing this transparently is not trivial.
|
|
|
|
*
|
|
|
|
* The Angular 2 router solves these problems. Using the router, you can declaratively specify
|
|
|
|
* application states, manage state transitions while taking care of the URL, and load bundles on
|
|
|
|
* demand.
|
|
|
|
*
|
|
|
|
* [Read this developer guide](https://angular.io/docs/ts/latest/guide/router.html) to get an
|
|
|
|
* overview of how the router should be used.
|
|
|
|
*
|
2016-08-17 18:35:30 -04:00
|
|
|
* @stable
|
2016-07-06 18:36:50 -04:00
|
|
|
*/
|
2016-07-27 12:54:19 -04:00
|
|
|
@NgModule({declarations: ROUTER_DIRECTIVES, exports: ROUTER_DIRECTIVES})
|
2016-07-07 14:59:08 -04:00
|
|
|
export class RouterModule {
|
2016-08-23 14:57:58 -04:00
|
|
|
constructor(@Optional() @Inject(ROUTER_FORROOT_GUARD) guard: any) {}
|
|
|
|
|
2016-09-10 19:53:27 -04:00
|
|
|
/**
|
|
|
|
* Creates a module with all the router providers and directives. It also optionally sets up an
|
|
|
|
* application listener to perform an initial navigation.
|
|
|
|
*
|
|
|
|
* Options:
|
|
|
|
* * `enableTracing` makes the router log all its internal events to the console.
|
|
|
|
* * `useHash` enables the location strategy that uses the URL fragment instead of the history
|
|
|
|
* API.
|
|
|
|
* * `initialNavigation` disables the initial navigation.
|
|
|
|
* * `errorHandler` provides a custom error handler.
|
|
|
|
*/
|
2016-07-27 12:54:19 -04:00
|
|
|
static forRoot(routes: Routes, config?: ExtraOptions): ModuleWithProviders {
|
|
|
|
return {
|
|
|
|
ngModule: RouterModule,
|
|
|
|
providers: [
|
2016-08-23 14:57:58 -04:00
|
|
|
ROUTER_PROVIDERS, provideRoutes(routes), {
|
|
|
|
provide: ROUTER_FORROOT_GUARD,
|
|
|
|
useFactory: provideForRootGuard,
|
|
|
|
deps: [[Router, new Optional(), new SkipSelf()]]
|
|
|
|
},
|
2016-08-01 18:51:22 -04:00
|
|
|
{provide: ROUTER_CONFIGURATION, useValue: config ? config : {}}, {
|
2016-07-28 15:10:36 -04:00
|
|
|
provide: LocationStrategy,
|
|
|
|
useFactory: provideLocationStrategy,
|
2016-07-28 17:36:05 -04:00
|
|
|
deps: [
|
|
|
|
PlatformLocation, [new Inject(APP_BASE_HREF), new Optional()], ROUTER_CONFIGURATION
|
|
|
|
]
|
2016-08-02 08:22:44 -04:00
|
|
|
},
|
2016-09-16 18:08:15 -04:00
|
|
|
{
|
|
|
|
provide: PreloadingStrategy,
|
|
|
|
useExisting: config && config.preloadingStrategy ? config.preloadingStrategy :
|
|
|
|
NoPreloading
|
|
|
|
},
|
2016-08-02 08:22:44 -04:00
|
|
|
provideRouterInitializer()
|
2016-07-27 12:54:19 -04:00
|
|
|
]
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-09-10 19:53:27 -04:00
|
|
|
/**
|
|
|
|
* Creates a module with all the router directives and a provider registering routes.
|
|
|
|
*/
|
2016-07-27 12:54:19 -04:00
|
|
|
static forChild(routes: Routes): ModuleWithProviders {
|
|
|
|
return {ngModule: RouterModule, providers: [provideRoutes(routes)]};
|
|
|
|
}
|
2016-07-18 06:50:31 -04:00
|
|
|
}
|
2016-07-28 15:10:36 -04:00
|
|
|
|
2016-08-01 18:51:22 -04:00
|
|
|
export function provideLocationStrategy(
|
2016-07-28 15:10:36 -04:00
|
|
|
platformLocationStrategy: PlatformLocation, baseHref: string, options: ExtraOptions = {}) {
|
|
|
|
return options.useHash ? new HashLocationStrategy(platformLocationStrategy, baseHref) :
|
|
|
|
new PathLocationStrategy(platformLocationStrategy, baseHref);
|
2016-08-16 16:40:28 -04:00
|
|
|
}
|
|
|
|
|
2016-08-23 14:57:58 -04:00
|
|
|
export function provideForRootGuard(router: Router): any {
|
|
|
|
if (router) {
|
2016-08-25 03:50:16 -04:00
|
|
|
throw new Error(
|
2016-08-23 14:57:58 -04:00
|
|
|
`RouterModule.forRoot() called twice. Lazy loaded modules should use RouterModule.forChild() instead.`);
|
|
|
|
}
|
|
|
|
return 'guarded';
|
|
|
|
}
|
|
|
|
|
2016-08-16 16:40:28 -04:00
|
|
|
/**
|
2016-09-10 19:53:27 -04:00
|
|
|
* @whatItDoes Registers routes.
|
|
|
|
*
|
|
|
|
* @howToUse
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* @NgModule({
|
|
|
|
* imports: [RouterModule.forChild(ROUTES)],
|
|
|
|
* providers: [provideRoutes(EXTRA_ROUTES)]
|
|
|
|
* })
|
|
|
|
* class MyNgModule {}
|
|
|
|
* ```
|
|
|
|
*
|
2016-08-16 16:40:28 -04:00
|
|
|
* @stable
|
|
|
|
*/
|
|
|
|
export function provideRoutes(routes: Routes): any {
|
|
|
|
return [
|
|
|
|
{provide: ANALYZE_FOR_ENTRY_COMPONENTS, multi: true, useValue: routes},
|
|
|
|
{provide: ROUTES, multi: true, useValue: routes}
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2016-09-10 19:53:27 -04:00
|
|
|
* @whatItDoes Represents options to configure the router.
|
2016-08-25 10:56:30 -04:00
|
|
|
*
|
2016-08-16 16:40:28 -04:00
|
|
|
* @stable
|
|
|
|
*/
|
|
|
|
export interface ExtraOptions {
|
2016-09-10 19:53:27 -04:00
|
|
|
/**
|
|
|
|
* Makes the router log all its internal events to the console.
|
|
|
|
*/
|
2016-08-16 16:40:28 -04:00
|
|
|
enableTracing?: boolean;
|
2016-09-10 19:53:27 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Enables the location strategy that uses the URL fragment instead of the history API.
|
|
|
|
*/
|
2016-08-16 16:40:28 -04:00
|
|
|
useHash?: boolean;
|
2016-09-10 19:53:27 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Disables the initial navigation.
|
|
|
|
*/
|
2016-08-25 11:48:31 -04:00
|
|
|
initialNavigation?: boolean;
|
2016-09-10 19:53:27 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A custom error handler.
|
|
|
|
*/
|
2016-08-25 10:56:30 -04:00
|
|
|
errorHandler?: ErrorHandler;
|
2016-09-16 18:08:15 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Configures a preloading strategy. See {@link PreloadAllModules}.
|
|
|
|
*/
|
|
|
|
preloadingStrategy?: any;
|
2016-08-16 16:40:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
export function setupRouter(
|
|
|
|
ref: ApplicationRef, urlSerializer: UrlSerializer, outletMap: RouterOutletMap,
|
|
|
|
location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler,
|
2016-10-20 13:44:44 -04:00
|
|
|
config: Route[][], opts: ExtraOptions = {}, urlHandlingStrategy?: UrlHandlingStrategy) {
|
|
|
|
const router = new Router(
|
2016-09-16 18:08:15 -04:00
|
|
|
null, urlSerializer, outletMap, location, injector, loader, compiler, flatten(config));
|
2016-08-16 16:40:28 -04:00
|
|
|
|
2016-10-20 13:44:44 -04:00
|
|
|
if (urlHandlingStrategy) {
|
|
|
|
router.urlHandlingStrategy = urlHandlingStrategy;
|
|
|
|
}
|
|
|
|
|
2016-08-25 10:56:30 -04:00
|
|
|
if (opts.errorHandler) {
|
2016-10-20 13:44:44 -04:00
|
|
|
router.errorHandler = opts.errorHandler;
|
2016-08-25 10:56:30 -04:00
|
|
|
}
|
|
|
|
|
2016-08-16 16:40:28 -04:00
|
|
|
if (opts.enableTracing) {
|
2016-10-20 13:44:44 -04:00
|
|
|
router.events.subscribe(e => {
|
2016-08-16 16:40:28 -04:00
|
|
|
console.group(`Router Event: ${(<any>e.constructor).name}`);
|
|
|
|
console.log(e.toString());
|
|
|
|
console.log(e);
|
|
|
|
console.groupEnd();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-10-20 13:44:44 -04:00
|
|
|
return router;
|
2016-08-16 16:40:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
export function rootRoute(router: Router): ActivatedRoute {
|
|
|
|
return router.routerState.root;
|
|
|
|
}
|
|
|
|
|
2016-09-16 18:08:15 -04:00
|
|
|
export function initialRouterNavigation(
|
|
|
|
router: Router, ref: ApplicationRef, preloader: RouterPreloader, opts: ExtraOptions) {
|
2016-08-25 11:48:31 -04:00
|
|
|
return () => {
|
2016-09-16 18:08:15 -04:00
|
|
|
router.resetRootComponentType(ref.componentTypes[0]);
|
|
|
|
preloader.setUpPreloading();
|
2016-08-25 11:48:31 -04:00
|
|
|
if (opts.initialNavigation === false) {
|
|
|
|
router.setUpLocationChangeListener();
|
|
|
|
} else {
|
|
|
|
router.initialNavigation();
|
|
|
|
}
|
|
|
|
};
|
2016-08-16 16:40:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
export function provideRouterInitializer() {
|
|
|
|
return {
|
|
|
|
provide: APP_BOOTSTRAP_LISTENER,
|
|
|
|
multi: true,
|
|
|
|
useFactory: initialRouterNavigation,
|
2016-09-16 18:08:15 -04:00
|
|
|
deps: [Router, ApplicationRef, RouterPreloader, ROUTER_CONFIGURATION]
|
2016-08-16 16:40:28 -04:00
|
|
|
};
|
2016-08-19 18:48:09 -04:00
|
|
|
}
|