docs(toh-5): add AppRoutingModule (#2584)
This commit is contained in:
parent
6f804c6534
commit
2e17d587de
|
@ -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 {}
|
|
@ -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
|
||||||
|
|
|
@ -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 {}
|
|
@ -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 { }
|
||||||
}
|
|
||||||
|
|
|
@ -644,17 +644,67 @@ block extract-id
|
||||||
Refresh the browser and select a hero from the dashboard; the app should navigate directly to that hero’s details.
|
Refresh the browser and select a hero from the dashboard; the app should navigate directly to that hero’s 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
|
||||||
|
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in New Issue