docs(toh-5): add AppRoutingModule (#2584)

This commit is contained in:
Ward Bell 2016-10-11 16:30:30 -07:00 committed by GitHub
parent 6f804c6534
commit 2e17d587de
6 changed files with 113 additions and 60 deletions

View File

@ -0,0 +1,20 @@
// #docregion
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent } from './dashboard.component';
import { HeroesComponent } from './heroes.component';
import { HeroDetailComponent } from './hero-detail.component';
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'detail/:id', component: HeroDetailComponent },
{ path: 'heroes', component: HeroesComponent }
];
@NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}

View File

@ -1,9 +1,7 @@
// #docplaster
// #docregion // #docregion
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { DashboardComponent } from './dashboard.component'; import { DashboardComponent } from './dashboard.component';
@ -11,44 +9,27 @@ import { HeroDetailComponent } from './hero-detail.component';
import { HeroesComponent } from './heroes.component'; import { HeroesComponent } from './heroes.component';
import { HeroService } from './hero.service'; import { HeroService } from './hero.service';
// #docregion routing-module
import { AppRoutingModule } from './app-routing.module';
@NgModule({ @NgModule({
imports: [ imports: [
BrowserModule, BrowserModule,
FormsModule, FormsModule,
RouterModule.forRoot([ AppRoutingModule
{
path: '',
redirectTo: '/dashboard',
pathMatch: 'full'
},
{
path: 'dashboard',
component: DashboardComponent
},
{
path: 'detail/:id',
component: HeroDetailComponent
},
{
path: 'heroes',
component: HeroesComponent
}
])
], ],
// #enddocregion routing // #enddocregion routing-module
// #docregion dashboard, hero-detail // #docregion dashboard
declarations: [ declarations: [
AppComponent, AppComponent,
DashboardComponent, DashboardComponent,
HeroDetailComponent, HeroDetailComponent,
HeroesComponent HeroesComponent
], ],
// #enddocregion dashboard, hero-detail // #enddocregion dashboard
providers: [ providers: [ HeroService ],
HeroService
],
bootstrap: [ AppComponent ] bootstrap: [ AppComponent ]
// #docregion routing // #docregion routing-module
}) })
export class AppModule { export class AppModule { }
} // #enddocregion routing-module

View File

@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent } from './dashboard.component';
import { HeroesComponent } from './heroes.component';
import { HeroDetailComponent } from './hero-detail.component';
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'detail/:id', component: HeroDetailComponent },
{ path: 'heroes', component: HeroesComponent }
];
@NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}

View File

@ -9,11 +9,12 @@ import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http'; import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';
import { AppRoutingModule } from './app-routing.module';
// #enddocregion v1 // #enddocregion v1
// Imports for loading & configuring the in-memory web api // Imports for loading & configuring the in-memory web api
import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; import { InMemoryWebApiModule } from 'angular-in-memory-web-api/in-memory-web-api.module';
import { InMemoryDataService } from './in-memory-data.service'; import { InMemoryDataService } from './in-memory-data.service';
// #docregion v1 // #docregion v1
@ -36,25 +37,7 @@ import { HeroSearchComponent } from './hero-search.component';
InMemoryWebApiModule.forRoot(InMemoryDataService), InMemoryWebApiModule.forRoot(InMemoryDataService),
// #enddocregion in-mem-web-api // #enddocregion in-mem-web-api
// #docregion v1 // #docregion v1
RouterModule.forRoot([ AppRoutingModule
{
path: '',
redirectTo: '/dashboard',
pathMatch: 'full'
},
{
path: 'dashboard',
component: DashboardComponent
},
{
path: 'detail/:id',
component: HeroDetailComponent
},
{
path: 'heroes',
component: HeroesComponent
}
])
], ],
// #docregion search // #docregion search
declarations: [ declarations: [
@ -67,10 +50,7 @@ import { HeroSearchComponent } from './hero-search.component';
// #docregion v1, v2 // #docregion v1, v2
], ],
// #enddocregion search // #enddocregion search
providers: [ providers: [ HeroService ],
HeroService,
],
bootstrap: [ AppComponent ] bootstrap: [ AppComponent ]
}) })
export class AppModule { export class AppModule { }
}

View File

@ -644,17 +644,67 @@ block extract-id
Refresh the browser and select a hero from the dashboard; the app should navigate directly to that heros details. Refresh the browser and select a hero from the dashboard; the app should navigate directly to that heros details.
.l-main-section .l-main-section
:marked
## Refactor routes to a _Routing Module_
Almost 20 lines of `AppModule` are devoted to configuring four routes.
Most application have many more routes and they [add guard services](../guide/router.html#guards)
to protect against unwanted or unauthorized navigations.
Routing considerations could quickly dominate this module and obscure its primary purpose which is to
establish key facts about the entire app for the Angular compiler.
We should refactor the routing configuration into its own class.
What kind of class?
The current `RouterModule.forRoot()` produces an Angular `ModuleWithProviders` which suggests that a
class dedicated to routing should be some kind of module.
It should be a [_Routing Module_](../guide/router.htm#routing-module).
By convention the name of a _Routing Module_ contains the word "Routing" and
aligns with the name of the module that declares the components navigated to".
Create an `app-routing.module.ts` file as a sibling to `app.module.ts`. Give it the following contents extracted from the `AppModule` class:
+makeExample('app/app-routing.module.ts')
:marked
Noteworthy points, typical of _Routing Modules_:
* Pull the routes into a variable. You might export it in future and it clarifies the _Routing Module_ pattern.
* Add `RouterModule.forRoot(routes)` to `imports`.
* Add `RouterModule` to `exports` so that the components in the companion module have access to Router declarables
such as `RouterLink` and `RouterOutlet`.
* No `declarations`! Declarations are the responsibility of the companion module.
* Add module `providers` for guard services if you have them; there are none in this example.
### Update _AppModule_
Now delete the routing configuration from `AppModule` and import the `AppRoutingModule`
(_both_ with an ES `import` statement _and_ by adding it to the `NgModule.imports` list).
Here is the revised `AppModule`, compared to its pre-refactor state:
+makeTabs(
`toh-5/ts/app/app.module.ts, toh-5/ts/app/app.module.3.ts`,
null,
`app/app.module.ts (after), app/app.module.ts (before)`)
:marked
It's simpler and focused on indentifying the key pieces of the application.
.l-main-section
:marked :marked
## Select a Hero in the *HeroesComponent* ## Select a Hero in the *HeroesComponent*
Earlier we added the ability to select a hero from the dashboard.
We'll do something similar in the `HeroesComponent`. We'll do something similar in the `HeroesComponent`.
That component's current template exhibits a "master/detail" style with the list of heroes The `HeroesComponent` template exhibits a "master/detail" style with the list of heroes
at the top and details of the selected hero below. at the top and details of the selected hero below.
+makeExample('toh-4/ts/app/app.component.ts','template', 'app/heroes.component.ts (current template)')(format=".") +makeExample('toh-4/ts/app/app.component.ts','template', 'app/heroes.component.ts (current template)')(format=".")
:marked :marked
Our goal is to move the detail to its own view and navigate to it when the user decides to edit a selected hero.
Delete the `<h1>` at the top (forgot about it during the `AppComponent`-to-`HeroesComponent` conversion). Delete the `<h1>` at the top (forgot about it during the `AppComponent`-to-`HeroesComponent` conversion).
Delete the last line of the template with the `<my-hero-detail>` tags. Delete the last line of the template with the `<my-hero-detail>` tags.
@ -663,8 +713,9 @@ block extract-id
We're going to display the hero detail on its own page and route to it as we did in the dashboard. We're going to display the hero detail on its own page and route to it as we did in the dashboard.
But we'll throw in a small twist for variety. But we'll throw in a small twist for variety.
When the user selects a hero from the list, we *won't* go to the detail page. We are keeping the "master/detail" style but shrinking the detail to a "mini", read-only version.
We'll show a *mini-detail* on *this* page instead and make the user click a button to navigate to the *full detail *page. When the user selects a hero from the list, we *don't* go to the detail page.
We show a *mini-detail* on *this* page instead and make the user click a button to navigate to the *full detail *page.
### Add the *mini-detail* ### Add the *mini-detail*
@ -859,6 +910,7 @@ block file-tree-end
.file app.component.css .file app.component.css
.file app.component.ts .file app.component.ts
.file app.module.ts .file app.module.ts
.file app-routing.module.ts
.file dashboard.component.css .file dashboard.component.css
.file dashboard.component.html .file dashboard.component.html
.file dashboard.component.ts .file dashboard.component.ts
@ -895,6 +947,7 @@ block file-tree-end
- We shared the `HeroService` among multiple components. - We shared the `HeroService` among multiple components.
- We moved HTML and CSS out of the component file and into their own files. - We moved HTML and CSS out of the component file and into their own files.
- We added the `uppercase` pipe to format data. - We added the `uppercase` pipe to format data.
- We refactored routes into a `Routing Module` that we import.
### The Road Ahead ### The Road Ahead

View File

@ -584,7 +584,7 @@ block filetree
- We configured an in-memory web API. - We configured an in-memory web API.
- We learned how to use !{_Observable}s. - We learned how to use !{_Observable}s.
Here are the files we added or changed in this chapter. Here are the files we _added or changed_ in this chapter.
block file-summary block file-summary
+makeTabs( +makeTabs(