0% found this document useful (0 votes)
109 views50 pages

Ngconf 2018 - Routing

This document discusses routing and navigation in Angular applications. It covers key routing concepts like router outlets, route resolvers, route guards, and feature modules. It shows examples of setting up routes and route configuration for components using the RouterModule and strategies for loading and resolving data before navigating to routes.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
109 views50 pages

Ngconf 2018 - Routing

This document discusses routing and navigation in Angular applications. It covers key routing concepts like router outlets, route resolvers, route guards, and feature modules. It shows examples of setting up routes and route configuration for components using the RouterModule and strategies for loading and resolving data before navigating to routes.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 50

N Things You Don’t Know

About the Router


N > 0
Deborah Kurata
Developer | Author | Consultant | MVP | GDE
@deborahkurata
How Routing Works
<a [routerLink]="['/movies']">Movie List</a>

{ path: 'movies', component: MovieListComponent }

movie-list.component.ts
<router-outlet></router-outlet> import { Component } from '@angular/core';

@Component({
  templateUrl: 'movie-list.component.html'
})
export class MovieListComponent { }
To Menu
or Not To Menu
app.component.html
<div class="container">
<nav class="navbar navbar-default">
<div class="container-fluid">
<a class="navbar-brand">{{pageTitle}}</a>
<ul class="nav navbar-nav">
<li><a [routerLink]="['/welcome']">Home</a></li>
<li><a [routerLink]="['/movies']">Movie List</a></li>
</ul>
</div>
</nav>
<div class="container">
<router-outlet></router-outlet>
</div>
</div>
app
router outlet
app.component.html
<div class="container">
<nav class="navbar navbar-default" *ngIf="displayMenu">
<div class="container-fluid">
<a class="navbar-brand">{{pageTitle}}</a>
<ul class="nav navbar-nav">
<li><a [routerLink]="['/welcome']">Home</a></li>
<li><a [routerLink]="['/movies']">Movie List</a></li>
</ul>
</div>
</nav>
<div class="container">
<router-outlet></router-outlet>
</div>
</div>
app.component.html
<router-outlet></router-outlet>
app
router outlet
app
router outlet
shell.component.html
<div class="container">
<nav class="navbar navbar-default">
<div class="container-fluid">
<a class="navbar-brand">{{pageTitle}}</a>
<ul class="nav navbar-nav">
<li><a [routerLink]="['/welcome']">Home</a></li>
<li><a [routerLink]="['/movies']">Movie List</a></li>
</ul>
</div>
</nav>
<div class="container">
<router-outlet></router-outlet>
</div>
</div>
shell.component.html
<mh-menu></mh-menu>

<div class='container'>
<router-outlet></router-outlet>
</div>
app
router outlet
shell
router outlet
app-routing.module.ts
RouterModule.forRoot([
{
path: '', component: ShellComponent,
children: [
{ path: 'welcome', component: WelcomeComponent },
{ path: 'movies', component: MovieListComponent },
{ path: '', redirectTo: 'welcome', pathMatch: 'full' }
]
},
{ path: 'login', component: LoginComponent },
{ path: '**', component: PageNotFoundComponent }
])
Preventing
Partial Page Display
Build a Resolver Service
movie.resolver.ts
@Injectable()
export class MovieResolver implements Resolve<IMovie> {

constructor(private movieService: MovieService) { }

resolve(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<IMovie> {
const id = route.paramMap.get('id');
return this.movieService.getMovie(+id);
}
}
Register the Resolver
app.module.ts
providers: [
MovieService,
MovieResolver
]
Add Resolver to Route
app-routing.module.ts
{
path: 'movies/:id',
resolve: { movie: MovieResolver },
component: MovieDetailComponent
},
Read Resolver Data
movie-detail.component.ts
ngOnInit(): void {
this.movie = this.route.snapshot.data['movie'];
}

app-routing.module.ts
{
path: 'movies/:id',
resolve: { movie: MovieResolver },
component: MovieDetailComponent
},
I'm Waiting …
Subscribe to Router Events
app.component.ts
constructor(private router: Router) {
router.events.subscribe((routerEvent: Event) => {
this.checkRouterEvent(routerEvent);
});
}
Check Router Events
app.component.ts
checkRouterEvent(routerEvent: Event): void {
if (routerEvent instanceof NavigationStart) {
this.loading = true;
}

if (routerEvent instanceof NavigationEnd ||


routerEvent instanceof NavigationCancel ||
routerEvent instanceof NavigationError) {
this.loading = false;
}
}
Display the Spinner
app.component.html
<span class="glyphicon glyphicon-refresh glyphicon-spin spinner"
*ngIf="loading"></span>
<router-outlet></router-outlet>
What’s going on?
app-routing.module.ts
RouterModule.forRoot([
{
path: '', component: ShellComponent,
children: [
{ path: 'welcome', component: WelcomeComponent },
{ path: 'movies', component: MovieListComponent },
{ path: '', redirectTo: 'welcome', pathMatch: 'full' }
]
},
{ path: 'login', component: LoginComponent },
{ path: '**', component: PageNotFoundComponent }
], { enableTracing: true })
Guards at the Ready
Build a Guard Service
movie-edit.guard.ts
@Injectable()
export class MovieEditGuard implements
CanDeactivate<MovieEditComponent> {

canDeactivate(component: MovieEditComponent): boolean {


if (component.isDirty) {
const title = component.movie.title || 'New Movie';
return confirm(`Lose all changes to ${title}?`);
}
return true;
}
}
Register the Guard
app.module.ts
providers: [
MovieService,
MovieResolver,
MovieEditGuard
]
Add Guard to Route
app-routing.module.ts
{
path: 'movies/:id/edit',
resolve: { movie: MovieResolver },
canDeactivate: [ MovieEditGuard ],
component: MovieEditComponent
}
Keep Constant
app-routing.module.ts
@NgModule({
imports: [
RouterModule.forRoot([
{
path: '', component: ShellComponent,
children: [
{ path: 'welcome', component: WelcomeComponent },
{ path: 'movies', component: MovieListComponent },
{ path: 'movies/:id', component: MovieDetailComponent },
{
path: 'movies/:id/edit', component: MovieEditComponent,
children: [
{ path: '', redirectTo: 'info', pathMatch: 'full' },
{ path: 'info', component: MovieEditInfoComponent },
{ path: 'tags', component: MovieEditTagsComponent }
]
},
{ path: '', redirectTo: 'welcome', pathMatch: 'full' }
]
},
{ path: 'login', component: LoginComponent },
{ path: '**', component: PageNotFoundComponent }
])
],
exports: [RouterModule]
})
export class AppRoutingModule { }
app-routing.module.ts
const appRoutes: Routes = [
{
path: '', component: ShellComponent,
children: [
{ path: 'welcome', component: WelcomeComponent },
{ path: 'movies', component: MovieListComponent },
{ path: 'movies/:id', component: MovieDetailComponent },
{ path: 'movies/:id/edit', component: MovieEditComponent,
children: [
{ path: '', redirectTo: 'info', pathMatch: 'full' },
{ path: 'info', component: MovieEditInfoComponent },
{ path: 'tags', component: MovieEditTagsComponent }
]
},
{ path: '', redirectTo: 'welcome', pathMatch: 'full' }
]
},
{ path: 'login', component: LoginComponent },
{ path: '**', component: PageNotFoundComponent }
];
app-routing.module.ts

@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [RouterModule]
})
export class AppRoutingModule { }
It’s a Feature
What About Feature Modules?
app-routing.module.ts
const appRoutes: Routes = [
{
path: '', component: ShellComponent,
children: [
{ path: 'welcome', component: WelcomeComponent },
{ path: 'movies', component: MovieListComponent },
{ path: 'movies/:id', component: MovieDetailComponent },
{ path: 'movies/:id/edit', component: MovieEditComponent,
children: [
{ path: '', redirectTo: 'info', pathMatch: 'full' },
{ path: 'info', component: MovieEditInfoComponent },
{ path: 'tags', component: MovieEditTagsComponent }
]
},
{ path: '', redirectTo: 'welcome', pathMatch: 'full' }
]
},
{ path: 'login', component: LoginComponent },
{ path: '**', component: PageNotFoundComponent }
];
movie.module.ts
const movieRoutes: Routes = [
{ path: 'movies', component: MovieListComponent } ,
{ path: 'movies/:id', component: MovieDetailComponent },
{ path: 'movies/:id/edit', component: MovieEditComponent,
children: [
{ path: '', redirectTo: 'info', pathMatch: 'full' },
{ path: 'info', component: MovieEditInfoComponent },
{ path: 'tags', component: MovieEditTagsComponent }
]
}
];

@NgModule({
imports: [ ...,
RouterModule.forChild(movieRoutes) // Won’t work!
], ...
})
export class MovieModule { }
imports: [
MovieModule, Merged Routes
RouterModule.forRoot(appRoutes)
] { path: 'movies', component: MovieListComponent } ,
{ path: 'movies/:id', component: MovieDetailComponent },
{ path: 'movies/:id/edit', component: MovieEditComponent,
children: [
{ path: '', redirectTo: 'info', pathMatch: 'full' },
{ path: 'info', component: MovieEditInfoComponent },
{ path: 'tags', component: MovieEditTagsComponent }
]
}
{ path: '', component: ShellComponent,
children: [
{ path: 'welcome', component: WelcomeComponent },
{ path: '', redirectTo: 'welcome', pathMatch: 'full' }
]
},
{ path: 'login', component: LoginComponent },
{ path: '**', component: PageNotFoundComponent }
Lazy Loading
From: Angular Routing course on Pluralsight
loadChildren
app-routing.module.ts
{
path: '', component: ShellComponent,
children: [
{ path: 'welcome', component: WelcomeComponent },
{
path: 'movies',
loadChildren: './movies/movie.module#MovieModule'
},
{ path: '', redirectTo: 'welcome', pathMatch: 'full' }
]
},
{ path: 'login', component: LoginComponent },
{ path: '**', component: PageNotFoundComponent }
movie.module.ts
const movieRoutes: Routes = [
{ path: '', component: MovieListComponent } ,
{ path: ':id', component: MovieDetailComponent },
{ path: ':id/edit', component: MovieEditComponent,
children: [
{ path: '', redirectTo: 'info', pathMatch: 'full' },
{ path: 'info', component: MovieEditInfoComponent },
{ path: 'tags', component: MovieEditTagsComponent }
]
}
];

@NgModule({
imports: [ ...,
RouterModule.forChild(movieRoutes)
], ...
})
export class MovieModule { }
For More Information

Twitter: @deborahkurata
Code: https://github.com/DeborahK/MovieHunter-
routing
Slides: bit.ly/ngConf18
Course: bit.ly/Angular-routing

You might also like