- var _example = 'toh-5'; block includes include ../_util-fns - var _appRoutingTsVsAppComp = 'app.module.ts' - var _RoutesVsAtRouteConfig = 'Routes' - var _RouterModuleVsRouterDirectives = 'RouterModule' - var _redirect = 'redirect' :marked There are new requirements for the Tour of Heroes app: * Add a *Dashboard* view. * Add the ability to navigate between the *Heroes* and *Dashboard* views. * When users click a hero name in either view, navigate to a detail view of the selected hero. * When users click a *deep link* in an email, open the detail view for a particular hero. When you’re done, users will be able to navigate the app like this: figure.image-display img(src='/resources/images/devguide/toh/nav-diagram.png' alt="View navigations") :marked To satisfy these requirements, you'll add Angular’s router to the app. .l-sub-section :marked For more information about the router, read the [Routing and Navigation](../guide/router.html) page. :marked When you're done with this page, the app should look like this . +ifDocsFor('ts|js') include ../../../_includes/_see-addr-bar .l-main-section :marked ## Where you left off Before continuing with the Tour of Heroes, verify that you have the following structure. block intro-file-tree .filetree .file angular-tour-of-heroes .children .file src .children .file app .children .file app.component.ts .file app.module.ts .file hero.service.ts .file hero.ts .file hero-detail.component.ts .file mock-heroes.ts .file main.ts .file index.html .file styles.css .file systemjs.config.js .file tsconfig.json .file node_modules ... .file package.json block keep-app-running :marked ## Keep the app transpiling and running Enter the following command in the terminal window: code-example(language="sh" class="code-shell"). npm start :marked This command runs the TypeScript compiler in "watch mode", recompiling automatically when the code changes. The command simultaneously launches the app in a browser and refreshes the browser when the code changes. :marked You can keep building the Tour of Heroes without pausing to recompile or refresh the browser. ## Action plan Here's the plan: * Turn `AppComponent` into an application shell that only handles navigation. * Relocate the *Heroes* concerns within the current `AppComponent` to a separate `HeroesComponent`. * Add routing. * Create a new `DashboardComponent`. * Tie the *Dashboard* into the navigation structure. .l-sub-section :marked *Routing* is another name for *navigation*. The router is the mechanism for navigating from view to view. .l-main-section :marked ## Splitting the *AppComponent* The current app loads `AppComponent` and immediately displays the list of heroes. The revised app should present a shell with a choice of views (*Dashboard* and *Heroes*) and then default to one of them. The `AppComponent` should only handle navigation, so you'll move the display of *Heroes* out of `AppComponent` and into its own `HeroesComponent`. ### *HeroesComponent* `AppComponent` is already dedicated to *Heroes*. Instead of moving the code out of `AppComponent`, rename it to `HeroesComponent` and create a separate `AppComponent` shell. Do the following: * Rename the app.component.ts file to heroes.component.ts. * Rename the `AppComponent` class to `HeroesComponent` (rename locally, _only_ in this file). * Rename the selector `my-app` to `my-heroes`. +makeExcerpt('src/app/heroes.component.ts (showing renamings only)', 'renaming') :marked ### Create *AppComponent* The new `AppComponent` is the application shell. It will have some navigation links at the top and a display area below. Perform these steps: * Create the file src/app/app.component.ts. * Define an exported `AppComponent` class. * Add an `@Component` !{_decorator} above the class with a `my-app` selector. * Move the following from `HeroesComponent` to `AppComponent`: * `title` class property. * `@Component` template `

` element, which contains a binding to `title`. * Add a `` element to the app template just below the heading so you still see the heroes. * Add `HeroesComponent` to the `!{_declsVsDirectives}` !{_array} of `!{_AppModuleVsAppComp}` so Angular recognizes the `` tags. * Add `HeroService` to the `providers` !{_array} of `!{_AppModuleVsAppComp}` because you'll need it in every other view. * Remove `HeroService` from the `HeroesComponent` `providers` !{_array} since it was promoted. * Add the supporting `import` statements for `AppComponent`. The first draft looks like this: block app-comp-v1 +makeTabs( `toh-5/ts/src/app/app.component.1.ts, toh-5/ts/src/app/app.module.1.ts`, ',', `src/app/app.component.ts (v1), src/app/app.module.ts (v1)`) :marked The app still runs and displays heroes. :marked ## Add routing Instead of displaying automatically, heroes should display after users click a button. In other words, users should be able to navigate to the list of heroes. Use the Angular router to enable navigation. block angular-router :marked The Angular router is an external, optional Angular NgModule called `RouterModule`. The router is a combination of multiple provided services (`RouterModule`), multiple directives (`RouterOutlet, RouterLink, RouterLinkActive`), and a configuration (`Routes`). You'll configure the routes first. :marked ### *<base href>* Open `index.html` and ensure there is a `` element (or a script that dynamically sets this element) at the top of the `` section. +makeExcerpt('src/index.html', 'base-href') .callout.is-important header base href is essential :marked For more information, see the [Set the base href](../guide/router.html#!#base-href) section of the [Routing and Navigation](../guide/router.html) page. a#configure-routes block router-config-intro :marked ### Configure routes Create a configuration file for the app routes. :marked *Routes* tell the router which views to display when a user clicks a link or pastes a URL into the browser address bar. Define the first route as a route to the heroes component. - var _file = _docsFor == 'dart' ? 'app.component.ts' : 'app.module.2.ts' +makeExcerpt('src/app/' + _file + ' (heroes route)', 'heroes') - var _are = _docsFor == 'dart' ? 'takes' : 'are' - var _routePathPrefix = _docsFor == 'dart' ? '/' : '' :marked The `!{_RoutesVsAtRouteConfig}` !{_are} !{_an} !{_array} of *route definitions*. This route definition has the following parts: - *Path*: The router matches this route's path to the URL in the browser address bar (`!{_routePathPrefix}heroes`).
  • *Name*: The official name of the route; it must begin with a capital letter to avoid confusion with the path (`Heroes`).
  • - *Component*: The component that the router should create when navigating to this route (`HeroesComponent`). .l-sub-section :marked Read more about defining routes with `!{_RoutesVsAtRouteConfig}` in the [Routing & Navigation](../guide/router.html) page. +ifDocsFor('ts|js') :marked ### Make the router available Import the `RouterModule` and add it to the `AppModule` imports !{_array}. +makeExcerpt('src/app/app.module.2.ts (app routing)', '') .l-sub-section :marked The `forRoot()` method is called because a configured router is provided at the app's root. The `forRoot()` method supplies the Router service providers and directives needed for routing, and performs the initial navigation based on the current browser URL. - var _heroesRoute = _docsFor == 'dart' ? "'Heroes'" : 'heroes' :marked ### Router outlet If you paste the path, `/heroes`, into the browser address bar at the end of the URL, the router should match it to the `!{_heroesRoute}` route and display the `HeroesComponent`. However, you have to tell the router where to display the component. To do this, you can add a `` element at the end of the template. `RouterOutlet` is one of the directives provided by the `!{_RouterModuleVsRouterDirectives}`. The router displays each component immediately below the `` as users navigate through the app. ### Router links Users shouldn't have to paste a route URL into the address bar. Instead, add an anchor tag to the template that, when clicked, triggers navigation to the `HeroesComponent`. The revised template looks like this: +makeExcerpt('src/app/app.component.1.ts', 'template-v2') block routerLink :marked Note the `routerLink` binding in the anchor tag. The `RouterLink` directive (another of the `RouterModule` directives) is bound to a string that tells the router where to navigate when the user clicks the link. Since the link is not dynamic, a routing instruction is defined with a one-time binding to the route path. Looking back at the route configuration, you can confirm that `'/heroes'` is the path of the route to the `HeroesComponent`. .l-sub-section :marked Read more about dynamic router links and the link parameters array in the [Appendix: Link Parameters Array](../guide/router.html#link-parameters-array) section of the [Routing & Navigation](../guide/router.html#) page. :marked Refresh the browser. The browser displays the app title and heroes link, but not the heroes list. .l-sub-section :marked The browser's address bar shows `/`. The route path to `HeroesComponent` is `/heroes`, not `/`. Soon you'll add a route that matches the path `/`. :marked Click the *Heroes* navigation link. The address bar updates to `/heroes` and the list of heroes displays. `AppComponent` now looks like this: +makeExample('src/app/app.component.1.ts', 'v2', 'src/app/app.component.ts (v2)') :marked The *AppComponent* is now attached to a router and displays routed views. For this reason, and to distinguish it from other kinds of components, this component type is called a *router component*. :marked ## Add a dashboard Routing only makes sense when multiple views exist. To add another view, create a placeholder `DashboardComponent`, which users can navigate to and from. +makeExcerpt('src/app/dashboard.component.1.ts (v1)', '') :marked You'll make this component more useful later. ### Configure the dashboard route To teach `!{_appRoutingTsVsAppComp}` to navigate to the dashboard, import the dashboard component and add the following route definition to the `!{_RoutesVsAtRouteConfig}` !{_array} of definitions. - var _file = _docsFor == 'dart' ? 'lib/app_component.dart' : 'src/app/app.module.3.ts' +makeExcerpt(_file + ' (Dashboard route)', 'dashboard') +ifDocsFor('ts|js') :marked Also import and add `DashboardComponent` to the `AppModule`'s `declarations`. +makeExcerpt('src/app/app.module.ts', 'dashboard') :marked ### Add a !{_redirect} route Currently, the browser launches with `/` in the address bar. When the app starts, it should show the dashboard and display a `/dashboard` URL in the browser address bar. block redirect-vs-use-as-default :marked To make this happen, use a redirect route. Add the following to the array of route definitions: +makeExcerpt('src/app/app.module.3.ts','redirect') .l-sub-section :marked Read more about *redirects* in the [Redirecting routes](../guide/router.html#!#redirect) section of the [Routing & Navigation](../guide/router.html#) page. :marked ### Add navigation to the template Add a dashboard navigation link to the template, just above the *Heroes* link. - var _vers = _docsFor == 'dart' ? '' : '.1' +makeExcerpt('src/app/app.component' + _vers + '.ts', 'template-v3') .l-sub-section :marked The `