Pluralsight - Angular Routing
Pluralsight - Angular Routing
INTRODUCTION
Deborah Kurata
CONSULTANT | SPEAKER | AUTHOR | MVP | GDE
@deborahkurata | blogs.msmvps.com/deborahk/
Module
Overview Sample Application
How Routing Works
Getting the Most from This Course
Course Outline
Page Not Found Welcome
Components
Message
App Log In
Product List
Product Detail
Edit Info
Imports Shared
...
Exports Module
Declarations
Providers
Bootstrap
How Routing Works
product-list.component.ts
import { Component } from '@angular/core';
<router-outlet></router-outlet> @Component({
templateUrl: 'product-list.component.html'
})
export class ProductListComponent { }
Url is
Changed
Display Process
Match Path
Template(s) Redirect
Activate Process
Component(s) Guards
Resolve
Data
Prerequisites
@deborahkurata
Blog Post
http://blogs.msmvps.com/deborahk/angular-routing-problem-solver/
Checklist
https://github.com/DeborahK/Angular-Routing
Routing Basics
Routing to Features
Course Route Parameters
Outline Prefetching Data using Route Resolvers
Child Routes
Grouping and Component-less Routes
Styling, Animating, and Watching Routes
Secondary (Auxiliary) Routes
Route Guards
Lazy Loading
App <router-outlet
<empty> <router-outlet> name="popup"> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Messages
Found
<empty> :id/edit :id
Data Data
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Routing Basics
Deborah Kurata
CONSULTANT | SPEAKER | AUTHOR | MVP | GDE
@deborahkurata | blogs.msmvps.com/deborahk/
Module
Overview
Setting up Basic Routing
HTML 5 vs. Hash-based Urls
App
<empty> <router-outlet> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Product List Messages
Found
Primary Routes
Secondary Routes
Child Routes
Setting up Routing
Define base path
Import Router
Configure routes
Place template
Activate routes
Defining the Base Path
Service
Configuration
RouterModule Directives
- RouterLink
- RouterLinkActive
- RouterOutlet
Importing the Angular Router
app.module.ts
import { RouterModule } from '@angular/router';
...
@NgModule({
imports: [
BrowserModule,
RouterModule
],
declarations: [
...
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Importing the Angular Router
RouterModule.forRoot() RouterModule.forChild()
Declares the router directives Declares the router directives
Manages our route configuration Manages our route configuration
Registers the router service Does NOT register the router service
Used once for the application Used in feature modules
Importing the Angular Router
app.module.ts
import { RouterModule } from '@angular/router';
...
@NgModule({
imports: [
BrowserModule,
RouterModule.forRoot([])
],
declarations: [
AppComponent
],
bootstrap: [AppComponent]
})
export class AppModule { }
App
<empty> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Product List Messages
Found
<router-outlet> <router-outlet>
Primary Routes
Secondary Routes
Child Routes </router-outlet> </router-outlet>
Configuring Routes
[
{ path: 'welcome', component: WelcomeComponent },
{ path: '', redirectTo: 'welcome', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent }
]
Redirects
[
{ path: 'home',
'welcome',
component:
component:
WelcomeComponent
WelcomeComponent
}, },
{ path: 'welcome',
'', redirectTo:
redirectTo:
'welcome',
'home',
pathMatch:
pathMatch:
'full'
'full'
}, },
{ path: '',
'**',
redirectTo:
component:'home',
'welcome',
PageNotFoundComponent
pathMatch:
pathMatch:
'full'
'full'
} }, },
]{ path: '**', component: PageNotFoundComponent }
]
Placing the Templates
app.component.html
...
...
Browser Server
www.mysite.com/APM/welcome APM/welcome
- APM
404! - index.html
Browser Url Styles
Browser Server
www.mysite.com/APM/welcome APM/index.html
- APM
index.html - index.html
Browser Url Styles
Browser Server
www.mysite.com/APM/#/welcome APM/
- APM
index.html - index.html
Using Hash-based Urls
app.module.ts
import { RouterModule } from '@angular/router';
...
@NgModule({
imports: [
BrowserModule,
RouterModule.forRoot([...], { useHash: true })
],
declarations: [
...
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Basics Checklist: Setting Up
Import RouterModule
- Use RouterModule.forRoot() for app
routes (one time only!)
- Use RouterModule.forChild() for features
@NgModule({
imports: [
...,
RouterModule.forRoot([])
], ...
})
Basics Checklist: Configuring Routes
path: Url segment(s) for the route
- No leading slash
- '' for default route; '**' for wildcard route
- Casing matters
component
- Not string name; not enclosed in quotes
- Component must be imported
Order matters!
{ path: 'welcome', component: WelcomeComponent },
{ path: '', redirectTo: 'welcome', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent }
Basics Checklist: Placing the Template
<router-outlet></router-outlet>
Basics Checklist: Activating a Route
Page Not
Welcome Log In Product List Messages
Found
Primary Routes
Secondary Routes
Child Routes
Routing to Features
Deborah Kurata
CONSULTANT | SPEAKER | AUTHOR | MVP | GDE
@deborahkurata | blogs.msmvps.com/deborahk/
Feature Module
An Angular module created with the express purpose of
organizing the components for a specific application
feature area.
BrowserModule HttpModule RouterModule ...
AppModule
Welcome
App Component
Component
Product Detail
Login Component
Component
Imports
Exports
Product Edit
Declarations Message Component
Component
Providers
Bootstrap
BrowserModule RouterModule
Feature Modules
HttpModule ...
Imports Shared
...
Exports Module
Declarations
Providers
Bootstrap
Module
Overview Setting up for Feature Routing
Route Path Naming Strategies
Activating a Route with Code
Accessing Feature Routes
Defining a Routing Module
App
<empty> <router-outlet> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Product List Messages
Found
Primary Routes
Secondary Routes
Child Routes
Setting up for Feature Routing
Import Router
Configure routes
Activate routes
Importing the Angular Router
Service
RouterModule Configuration
Directives
Importing the Angular Router
product.module.ts
import { RouterModule } from '@angular/router';
...
@NgModule({
imports: [
SharedModule,
RouterModule.forChild([])
],
declarations: [
ProductListComponent,
...
],
...
})
export class ProductModule { }
Route Path Naming Strategies
Product Product
List List
products products
Product Product
Detail Detail
product/:id products/:id
Product Product
Edit Edit
productEdit/:id products/:id/edit
App
<empty> <router-outlet> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Product List Messages
Found
products/:id products/:id/edit
Product
Product Edit
Detail
Primary Routes
Secondary Routes
Child Routes
Activating a Route with Code
Activating a Route with Code
app.component.ts
import { Router } from '@angular/router';
...
@Component({...})
export class AppComponent {
...
constructor(private router: Router) { }
logOut(): void {
// Do some processing
this.router.navigate(['/welcome']);
}
}
Activating a Route with Code
this.router.navigate(['/welcome']); // Standard syntax
http://localhost:3000/welcome(popup:messages) // navigate()
http://localhost:3000/welcome // navigateByUrl()
Demo
• Better organization
• Easier to find
• Separation of concerns
Matching Routes
app.module.ts Route Paths
imports: [
BrowserModule,
HttpModule, welcome
AppRoutingModule,
ProductModule,
''
UserModule,
MessageModule
**
] products
login
Matching Routes
app.module.ts Route Paths
imports: [
BrowserModule,
HttpModule, products
ProductModule,
UserModule,
login
MessageModule,
AppRoutingModule
welcome
] ''
**
Defining a Configuration Constant
app-routing.module.ts
const ROUTES = [
{ path: 'welcome', component: WelcomeComponent },
{ path: '', redirectTo: 'welcome', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent }
];
@NgModule({
imports: [
RouterModule.forRoot(ROUTES)
],
exports: [ RouterModule ]
})
export class AppRoutingModule { }
Routing to Features Checklist: Configuration
Import RouterModule
- Be sure to use RouterModule.forChild()
this.router.navigateByUrl('/welcome');
Routing to Features Checklist: Routing Modules
Page Not
Welcome Log In Product List Messages
Found
products/:id products/:id/edit
Product
Product Edit
Detail
Primary Routes
Secondary Routes
Child Routes
Route Parameters
Deborah Kurata
CONSULTANT | SPEAKER | AUTHOR | MVP | GDE
@deborahkurata | blogs.msmvps.com/deborahk/
http://localhost:3000/products/5
Module
Required Parameters
Overview
- Configure
- Populate
- Read
Optional Parameters
Query Parameters
App
<empty> <router-outlet> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Product List Messages
Found
products/:id products/:id/edit
Product
Product Edit
Detail
Primary Routes
Secondary Routes
Child Routes
Configuring Routes with Placeholders
Angular Module
[
{ path: 'products', component: ProductListComponent },
{ path: 'products/:id', component: ProductDetailComponent },
{ path: 'products/:id/edit', component: ProductEditComponent }
]
Configuring Routes with Placeholders
Angular Module
[
{ path: 'orders', component: OrderListComponent },
{ path: 'orders/:id', component: OrderDetailComponent },
{ path: 'orders/:id/items/:itemId', component: OrderItemDetailComponent }
]
Populating Route Parameters
Template
Component Class
this.router.navigate(['/products', this.product.id]);
Reading Route Parameters
ActivatedRoute Service
Url Route Query Resolver
…
segments parameters parameters data
Reading Route Parameters
Component Class
constructor(private route: ActivatedRoute) { }
Snapshot
let id = this.route.snapshot.params['id'];
Observable
this.route.params.subscribe(
params => {
let id = params['id'];
}
);
Reading Route Parameters: Snapshot
Component Class
import { ActivatedRoute } from '@angular/router';
...
constructor(private route: ActivatedRoute) {
console.log(this.route.snapshot.params['id']);
}
Angular Module
{ path: 'products/:id', component: ProductDetailComponent }
Template
<a [routerLink]="['/products', product.id]">{{product.productName}}</a>
Reading Route Parameters: Observable
Component Class
import { ActivatedRoute } from '@angular/router';
...
constructor(private route: ActivatedRoute) {
this.route.params.subscribe(
params => {
console.log(params['id']);
}
);
}
Angular Module
{ path: 'products/:id/edit', component: ProductEditComponent }
Template
<a [routerLink]="['/products', product.id, 'edit']">Edit</a>
Reading Route Parameters
Snapshot Observable
To read the parameters only once To watch for parameter changes
Simple code More complex code
let id = this.route.params.subscribe(
this.route.snapshot.params['id']; params => {
let id = params['id']);
}
);
Reading Route Parameters (v4+)
Component Class
import { ActivatedRoute } from '@angular/router';
...
constructor(private route: ActivatedRoute) {
console.log(this.route.snapshot.paramMap.get('id'));
}
[routerLink]="['/products',
productName, productCode, availabilityStart, availabilityEnd]"
http://localhost:3000/products/Controller/gmg/March%201%2C%202015/March%201%2C%202017
{ path: 'products/:name/:code/:startDate/:endDate',
component: ProductListComponent }
With Optional
Parameters
March 1, 2015
http://localhost:3000/products;name=Controller;code=gmg;
startDate=March%201%2C%202015;endDate=March%201%2C%202017
Template
[routerLink]="['/products', {name: productName, code: productCode,
startDate: availabilityStart, endDate: availabilityEnd}]"
http://localhost:3000/products/5?filterBy=er&showImage=true
http://localhost:3000/products?filterBy=er&showImage=true
Defining Query Parameters
Template
<a [routerLink] = "['/products', product.id]"
product.id]">
[queryParams] = "{ filterBy: 'er', showImage: true }">
{{product.productName}}
{{product.productName}}
</a>
</a>
Component Class
this.router.navigate(['/products'],
{
queryParams: { filterBy: 'er', showImage: true }
}
);
Angular Module
Component Class
this.router.navigate(['/products'],
{ preserveQueryParams: true }
);
Retaining Query Parameters (v4+)
Template
<a [routerLink] = "['/products']"
queryParamsHandling = "preserve">
Back
</a>
Component Class
this.router.navigate(['/products'],
{ queryParamsHandling: 'preserve' }
);
Reading Query Parameters
ActivatedRoute Service
Url Route Query Resolver
…
segments parameters parameters data
Reading Query Parameters
Component Class
import { ActivatedRoute } from '@angular/router';
Template
<a [routerLink] = "['/products', product.id]"
[queryParams] = "{ filterBy: listFilter, showImage: showImage }">
{{product.productName}}
</a>
Route Parameters Checklist: Required Parameters
Populate
<a [routerLink]="['/products', product.id]">...</a>
this.router.navigate(['/products', this.product.id]);
Read
this.route.snapshot.params['id'];
Or Observable
Route Parameters Checklist: Optional Parameters
this.router.navigate(['/products',
{start: startDate, end: endDate}]);
Read
this.route.snapshot.params['start'];
Or Observable
Route Parameters Checklist: Query Parameters
this.router.navigate(['/products', {
queryParams: { filterBy: 'x', showImage: true }
}]);
Read
this.route.snapshot.queryParams['filterBy'];
Or Observable
Required Parameters
Summary
- Configure
- Populate
- Read
Optional Parameters
Query Parameters
App
<empty> <router-outlet> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Product List Messages
Found
products/:id products/:id/edit
Product
Product Edit
Detail
Primary Routes
Secondary Routes
Child Routes
Prefetching Data Using Route Resolvers
Deborah Kurata
CONSULTANT | SPEAKER | AUTHOR | MVP | GDE
@deborahkurata | blogs.msmvps.com/deborahk/
Benefits of Prefetching Data
Page Not
Welcome Log In Product List Messages
Found
products/:id products/:id/edit
Product
Product Edit
Detail
Primary Routes
Secondary Routes
Child Routes
Providing Data with a Route
Optional
Route Query
Route
Parameters Parameters
Parameters
Component Class
this.pageTitle = this.route.snapshot.data['pageTitle'];
Without a Route Resolver
Web Server
Data
DB
/products/5
Router
With a Route Resolver
Web Server
Data
DB
/products/5
Router
Data
Using a Route Resolver
@Injectable()
export class ProductResolver implements Resolve<IProduct> {
resolve(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<IProduct> {
...
}
}
Adding a Resolver to a Route Configuration
Angular Module
[
{ path: 'products', component: ProductListComponent },
{ path: 'products/:id', component: ProductDetailComponent,
resolve: { product: ProductResolver }},
{ path: 'products/:id/edit', component: ProductEditComponent,
resolve: { product: ProductResolver }}
]
Adding a Resolver to a Route Configuration
Angular Module
[
{ path: 'products', component: ProductListComponent },
{ path: 'products/:id', component: ProductDetailComponent,
resolve: { product: ProductResolver }},
{ path: 'products/:id/edit', component: ProductEditComponent,
resolve: { product: ProductResolver,
categories: CategoryResolver }}
]
Reading Resolver Data: Snapshot
Component Class
import { ActivatedRoute } from '@angular/router';
...
product: IProduct;
Angular Module
{ path: 'products/:id', component: ProductDetailComponent,
resolve: { product: ProductResolver } }
Resolver Service
export class ProductResolver implements Resolve<IProduct> { }
Sharing the Data Instance
Router
Data:
product
Component Class 1
this.product = this.route.snapshot.data['product'];
Component Class 2
this.product = this.route.snapshot.data['product'];
Reading Resolver Data: Observables
Component Class
import { ActivatedRoute } from '@angular/router';
...
product: IProduct;
constructor(private route: ActivatedRoute) {
this.route.data.subscribe(
data => this.product = data['product'];
);
}
Angular Module
{ path: 'products/:id/edit', component: ProductEditComponent,
resolve: { product: ProductResolver } }
Resolver Service
export class ProductResolver implements Resolve<IProduct> { }
Route Resolvers Checklist: Building
resolve(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<IProduct> { }
Route Resolvers Checklist: Configuring
this.product = this.route.snapshot.data['product'];
- Data Observable
this.route.data.subscribe(
data => this.product = data['product'];
);
Providing Data with a Route
Page Not
Welcome Log In Product List Messages
Found
products/:id products/:id/edit
Product
Product Edit
Detail
Primary Routes
Secondary Routes
Child Routes
Child Routes
Deborah Kurata
CONSULTANT | SPEAKER | AUTHOR | MVP | GDE
@deborahkurata | blogs.msmvps.com/deborahk/
App
/welcome /products
Welcome
/ /:id/edit /:id
Product
Product List Product Edit
Detail
/info /tags
Page Not
Welcome Log In Product List Messages
Found
products/:id products/:id/edit
Product
Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Secondary Routes Edit Info Edit Tags
Child Routes
Primary Router Outlet
app.component.html
<div>
<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]="['/products']">Product List</a></li>
<li><a [routerLink]="['/products', 0, 'edit']">Add Product</a></li>
</ul>
...
</div>
</nav>
<div class="container">
<router-outlet></router-outlet>
</div>
</div>
<router-outlet>
<router-outlet></router-outlet>
</router-outlet>
<router-outlet>
</router-outlet>
<router-outlet>
<router-outlet></router-outlet>
</router-outlet>
<router-outlet>
<router-outlet>
</router-outlet>
</router-outlet>
Child Routes
Tabbed pages
Master/detail layouts
Embedded templates
Feature modules
Lazy loading
App
<router-outlet>
welcome products products/:id/edit products/:id
Product
Welcome Product List Product Edit
Detail
<router-outlet>
info tags
<router-outlet></router-outlet>
</div>
Activating Child Routes
Template
// Absolute path
<a [routerLink]="['/products', product.id, 'edit', 'info']">Info</a>
// Relative path
<a [routerLink]="['info']">Info</a>
Component Class
// Absolute path
this.router.navigate(['/products', this.product.id, 'edit', 'info']);
// Relative path
this.router.navigate(['info'], { relativeTo: this.route });
Obtaining Data for a Child Route
Product Data Service
•@
this.productService.getProduct(id)
•@
.subscribe(product => this.product = product);
•@
•@
Product
Welcome Product List Product Edit
Detail
<router-outlet>
info tags
<router-outlet></router-outlet>
</div>
Child Routes: Activating
this.product = this.route.snapshot.data['product'];
- Data Observable
this.route.data.subscribe(
data => this.product = data['product'];
);
Using Child Routes
Summary Configuring Child Routes
Placing the Child View
Activating Child Routes
Obtaining Data for Child Routes
Validating Across Child Routes
App
<empty> <router-outlet> (popup:
welcome login products ** messages)
Data Data
Page Not
Welcome Log In Product List Messages
Found
products/:id products/:id/edit
Product
Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Secondary Routes Edit Info Edit Tags
Child Routes
Grouping and Component-less Routes
Deborah Kurata
CONSULTANT | SPEAKER | AUTHOR | MVP | GDE
@deborahkurata | blogs.msmvps.com/deborahk/
App
<router-outlet>
/welcome /products
Welcome
/ /:id/edit /:id
Product
Product List Product Edit
Detail
<router-outlet>
/info /tags
Better organization
Share resolvers and guards
Lazy loading
Module
Overview
Grouping Routes
Component-less Routes
App
<empty> <router-outlet> (popup:
welcome login products ** messages)
Data Data
Page Not
Welcome Log In Product List Messages
Found
products/:id products/:id/edit
Product
Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Secondary Routes Edit Info Edit Tags
Child Routes
App
<empty> <router-outlet> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Messages
Found
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Grouping Routes
RouterModule.forChild([ RouterModule.forChild([
{ {
path: 'products', path: 'products',
component: ProductListComponent component: ProductListComponent,
}, children: [
{ {
path: 'products/:id', path: ':id',
component: ProductDetailComponent, component: ProductDetailComponent,
resolve: { product: ProductResolver } resolve: { product: ProductResolver }
}, },
{ {
path: 'products/:id/edit', path: ':id/edit',
component: ProductEditComponent, component: ProductEditComponent,
resolve: { product: ProductResolver }, resolve: { product: ProductResolver },
children: [...] children: [...]
} }
]) ]
])
<router-outlet>
<router-outlet></router-outlet>
</router-outlet>
<router-outlet>
<router-outlet>
</router-outlet>
</router-outlet>
<router-outlet>
<router-outlet></router-outlet>
</router-outlet>
Component-less Route
RouterModule.forChild([ RouterModule.forChild([
{ {
path: 'products', path: 'products',
component: ProductListComponent, children: [
children: [ {
{ path: '',
path: ':id', component: ProductListComponent
component: ProductDetailComponent, },
resolve: { product: ProductResolver } {
}, path: ':id',
{ component: ProductDetailComponent,
path: ':id/edit', resolve: { product: ProductResolver }
component: ProductEditComponent, },
resolve: { product: ProductResolver }, {
children: [...] path: ':id/edit',
} component: ProductEditComponent,
] resolve: { product: ProductResolver },
]) children: [...]
}
]
])
App
<empty> <router-outlet> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Messages
Found
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Checklist: Grouping
RouterModule.forChild([
{
path: 'products',
component: ProductListComponent,
children: [
{ Define routes as children of one
path: ':id', parent route
component: ProductDetailComponent,
resolve: { product: ProductResolver }
},
Specify relative paths
{
path: ':id/edit', But grouping alone is not sufficient!
component: ProductEditComponent,
resolve: { product: ProductResolver },
children: [...]
}
]
])
Checklist: Component-less Routes
RouterModule.forChild([
{
path: 'products',
children: [
{ Add a default path that routes to the
path: '',
component: ProductListComponent desired component
},
{ Remove the component from the
path: ':id', parent route
component: ProductDetailComponent,
resolve: { product: ProductResolver } The child routes are displayed in a
},
{ higher-level outlet
path: ':id/edit',
component: ProductEditComponent,
resolve: { product: ProductResolver },
children: [...]
}
])
Summary
Grouping Routes
Component-less Routes
App
<empty> <router-outlet> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Messages
Found
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Styling, Animating, and
Watching Routes
Deborah Kurata
CONSULTANT | SPEAKER | AUTHOR | MVP | GDE
@deborahkurata | blogs.msmvps.com/deborahk/
Module
Overview Styling the Selected Route
Animating Route Transitions
Watching Routing Events
Reacting to Routing Events
App
<empty> <router-outlet> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Messages
Found
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Styling the Selected Route
Styling the Selected Route
Template
NavigationCancel NavigationError
Watching Routing Events
app-routing.module.ts
imports: [
RouterModule.forRoot([
{ path: 'welcome', component: WelcomeComponent },
{ path: '', redirectTo: 'welcome', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent }
], { enableTracing: true })
],
...
Reacting to Routing Events
Display a spinner
Log actions
Execute logic
Reacting to Routing Events
Component Class
Page Not
Welcome Log In Messages
Found
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Secondary Routes
Deborah Kurata
CONSULTANT | SPEAKER | AUTHOR | MVP | GDE
@deborahkurata | blogs.msmvps.com/deborahk/
<app-graph> <app-stats>
<app-pie> <app-map>
<router-outlet> <router-outlet>
<router-outlet> <router-outlet>
Module
Overview Using Secondary Routes
Defining a Named RouterOutlet
Configuring Secondary Routes
Activating Secondary Routes
Clearing Secondary Outlets
App <router-outlet
<empty> <router-outlet> name="popup"> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Messages
Found
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Primary Router Outlet
app.component.html
<div>
<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]="['/products']">Product List</a></li>
<li><a [routerLink]="['/products', 0, 'edit']">Add Product</a></li>
</ul>
...
</div>
</nav>
<div class="container">
<router-outlet></router-outlet>
</div>
</div>
<router-outlet> <router-outlet>
</router-outlet> </router-outlet>
Secondary Routes
Dashboard
Multi-window user interface
Notes or comments
Messages
…
<router-outlet> <router-outlet>name="popup">
<router-outlet
</router-outlet> </router-outlet>
</router-outlet>
</router-outlet> </router-outlet>
Configuring Secondary Routes
Angular Module
RouterModule.forChild([
{
path: 'messages',
component: MessageComponent,
outlet: 'popup'
},
])
<router-outlet> App <router-outlet name="popup">
Welcome Log In
Product
Message
<empty> :id/edit :id Summary
this.router.navigate([{ outlets: {
primary: ['/products', product.id, 'edit'],
popup: ['summary', product.id]
}}]);
this.router.navigateByUrl('/products/5/edit(popup:summary/5)');
Clearing Secondary Outlets
Template
Component Class
this.router.navigateByUrl('/login');
Secondary Routes: Named RouterOutlet
<router-outlet name='popup'></router-outlet>
</div>
Secondary Routes: Configuring
Page Not
Welcome Log In Messages
Found
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Route Guards
Deborah Kurata
CONSULTANT | SPEAKER | AUTHOR | MVP | GDE
@deborahkurata | blogs.msmvps.com/deborahk/
Protecting Routes with Guards
canActivate
- Guard navigation to a route
canActivateChild
- Guard navigation to a child route
canDeactivate
- Guard navigation away from a route
canLoad
- Prevent asynchronous routing
resolve
- Prefetch data before activating a route
Module
Overview Using Route Guards
canActivate Guard
Sharing Data with a Guard
canActivateChild Guard
canDeactivate Guard
App <router-outlet
<empty> <router-outlet> name="popup"> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Messages
Found
<empty> :id/edit :id
Data Data
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Using Route Guards
canDeactivate
canLoad
canActivateChild
canActivate
resolve
Building a Guard Service
auth-guard.service.ts
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(): boolean {
...
}
}
Registering a Guard
Angular Module
...
import { AuthGuard } from './auth-guard.service';
@NgModule({
imports: [...],
declarations: [...],
providers: [ AuthGuard, ... ]
})
export class UserModule { }
Guarding a Route
Angular Module
...
import { AuthGuard } from './auth-guard.service';
...
{
path: ':id',
component: ProductDetailComponent,
resolve: { product: ProductResolver },
canActivate: [ AuthGuard ]
}
Sharing Guards
RouterModule.forChild([
{
path: 'products',
children: [
{
path: '',
component: ProductListComponent
},
{
path: ':id',
component: ProductDetailComponent,
resolve: { product: ProductResolver }
},
{
path: ':id/edit',
component: ProductEditComponent,
resolve: { product: ProductResolver },
children: [...]
}
]
])
Guarding a Route
Register the
Build a guard Add the guard
service in an
service to a route
Angular module
canActivate Guard
Page Not
Welcome Log In Messages
Found
<empty> :id/edit :id
Data Data
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
canDeactivate Guard
Build a service
Implement the guard type
Create the associated method
Register the service provider
@NgModule({
import { Injectable
Add } from '@angular/core';
the guard to a route
import { CanActivate } from
imports: [...],'@angular/router';
{ declarations: [...],
@Injectable()
path: ':id', [ AuthGuard, ... ]
providers:
export classcanActivate:
AuthGuard implements CanActivate
[ AuthGuard ], {
})
component: ProductDetailComponent
canActivate(): boolean {...}
}
},
Summary Using Route Guards
canActivate Guard
Sharing Data with a Guard
canActivateChild Guard
canDeactivate Guard
App <router-outlet
<empty> <router-outlet> name="popup"> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Messages
Found
<empty> :id/edit :id
Data Data
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Lazy Loading
Deborah Kurata
CONSULTANT | SPEAKER | AUTHOR
@deborahkurata | blogs.msmvps.com/deborahk/
Web
Web Browser Server
index.html
Response
App Files
Web
Web Browser Server
index.html
Response
App Files
Lazy
Loaded
Files
Module
Overview Preparing for Lazy Loading
Lazy Loading
canLoad Guard
Preloading Feature Modules
Custom Loading Strategies
App <router-outlet
<empty> <router-outlet> name="popup"> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Messages
Found
<empty> :id/edit :id
Data Data
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Preparing for Lazy Loading
Navigate Download
Download
Launch Template to a lazy lazy Template
imported
application appears loaded loaded appears
modules
feature module
Navigate
Download
Launch Template Preload to lazy Template
imported
application appears modules loaded appears
modules
feature
Preload Strategies
No
Preload all Custom
preloading
Preload All Strategy
app-routing.module.ts
import { RouterModule, PreloadAllModules } from '@angular/router';
...
RouterModule.forRoot([
{ path: 'welcome', component: WelcomeComponent },
{
path: 'products',
loadChildren: 'app/products/product.module#ProductModule'
},
...
], { preloadingStrategy: PreloadAllModules })
canLoad guard
blocks
preloading
Preload Strategies
No
Preload all Custom
preloading
Custom Preloading Strategy
Set the
Build a Register the
preloading
preloading service in an
strategy routing
strategy service Angular module
option
Building a Preload Strategy Service
selective-strategy.service.ts
import { Injectable } from '@angular/core';
import { PreloadingStrategy } from '@angular/router';
import { Observable } from '@angular/router';
@Injectable()
export class SelectiveStrategy implements PreloadingStrategy {
@NgModule({
imports: [
RouterModule.forRoot([
{ path: 'welcome', component: WelcomeComponent },
{
path: 'products',
loadChildren: 'app/products/product.module#ProductModule'
}, ...
], { preloadingStrategy: SelectiveStrategy }),
],
providers: [ SelectiveStrategy, ... ]
})
export class AppModule { }
Lazy Loading Checklist: Preparing
{
path: 'products',
loadChildren: 'app/products/product.module#ProductModule'
}
Lazy Loading Checklist: Preloading
Page Not
Welcome Log In Messages
Found
<empty> :id/edit :id
Data Data
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Final Words
Deborah Kurata
CONSULTANT | SPEAKER | AUTHOR
@deborahkurata | blogs.msmvps.com/deborahk/
App
<empty> <router-outlet>
welcome **
Page Not
Welcome
Found
Primary Routes
Secondary Routes
Child Routes
App
<empty> <router-outlet>
welcome login products **
Page Not
Welcome Log In Product List
Found
Primary Routes
Secondary Routes
Child Routes
App
<empty> <router-outlet>
welcome login products **
Page Not
Welcome Log In Product List
Found
products/:id products/:id/edit
Product
Product Edit
Detail
Primary Routes
Secondary Routes
Child Routes
App
<empty> <router-outlet>
welcome login products **
Data Data
Page Not
Welcome Log In Product List
Found
products/:id products/:id/edit
Product
Product Edit
Detail
Primary Routes
Secondary Routes
Child Routes
App
<empty> <router-outlet>
welcome login products **
Data Data
Page Not
Welcome Log In Product List
Found
products/:id products/:id/edit
Product
Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Secondary Routes Edit Info Edit Tags
Child Routes
App
<empty> <router-outlet>
welcome login products **
Page Not
Welcome Log In
Found
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
App
<empty> <router-outlet>
welcome login products **
Page Not
Welcome Log In
Found
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
App <router-outlet
<empty> <router-outlet> name="popup">
welcome login products ** (popup: messages)
Page Not
Welcome Log In Messages
Found
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
App <router-outlet
<empty> <router-outlet> name="popup"> (popup:
welcome login products ** messages)
Page Not
Welcome Log In Messages
Found
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
App <router-outlet
<empty> <router-outlet> name="popup">
welcome login products ** (popup: messages)
Page Not
Welcome Log In Messages
Found
Product
Product List Product Edit
Detail
<router-outlet>
info tags
Primary Routes
Edit Info Edit Tags
Secondary Routes
Child Routes
Checklist
Book
- "Angular Router" by Victor Savkin
• https://leanpub.com/router
@deborahkurata