0% found this document useful (0 votes)
48 views

Pluralsight - Angular Routing

Uploaded by

Iulian Sirbu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
48 views

Pluralsight - Angular Routing

Uploaded by

Iulian Sirbu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 261

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

Primary Routes Product Edit


Child Routes
Secondary Routes
Edit Tags
BrowserModule RouterModule
Angular Modules
HttpModule ...

App Module Product User Module Message


Module Module
Product List
App Component Login Component Message Component
Component

Welcome Product Detail


Component Component

Page Not Found Product Edit


Component Component

Imports Shared
...
Exports Module
Declarations
Providers
Bootstrap
How Routing Works

<a [routerLink]="['/products']">Product List</a>

{ path: 'products', component: ProductListComponent }

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

Required Suggested Not Required

• Angular modules • Angular 2: Getting • Extensive routing


(NgModule) Started experience
• Components • Angular 2: First
• Templates Look
• Services
Thoughts? Comments? Questions?

@deborahkurata
Blog Post
http://blogs.msmvps.com/deborahk/angular-routing-problem-solver/
Checklist

Review module concepts


Code along assistance
Revisit as you implement routing
GitHub Repository

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

Used by the router


- Building the Url for navigation
www.mySite.com/APM/
Used by the browser
- Building the Url for downloading and
linking
<base href="/">  For development:
http://localhost:3000

<base href="/APM/">  For deployment:


http://www.mySite.com/APM/
Resetting the Base Path

<base href="/"> Manually reset the base path

(http://localhost:3000) Use a task runner


Use the Angular CLI
- ng build --base-href /APM/
<base href="/APM/"> - ng build --bh /APM/
(www.mySite.com/APM/)
Importing the Angular Router

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
...

<ul class='nav navbar-nav'>


<li><a [routerLink]="['/welcome']">Home</a></li>
<li><a [routerLink]="['/products']">Product List</a></li>
</ul>
<router-outlet></router-outlet>
Navigating the Application Routes

Menu option, link, image or button that


activates a route
Typing the Url in the address bar /
bookmark
The browser's forward or back buttons
Activating a Route
app.component.html
...

<ul class='nav navbar-nav'>


<li><a [routerLink]="['/welcome']">Home</a></li>
<li><a [routerLink]="['/products']">Product List</a></li>
</ul>
<router-outlet></router-outlet>

...

<ul class='nav navbar-nav'>


<li><a routerLink="/welcome">Home</a></li>
<li><a routerLink="/products">Product List</a></li>
</ul>
<router-outlet></router-outlet>
Browser Url Styles
Browser Url Styles

HTML 5 Style (…/welcome) Hash-based (…/#/welcome)


Leverages HTML 5 history pushState Leverages Url fragments
Default
More natural Url
Requires Url rewriting

Browser Server
www.mysite.com/APM/welcome APM/welcome
- APM
404! - index.html
Browser Url Styles

HTML 5 Style (…/welcome) Hash-based (…/#/welcome)


Leverages HTML 5 history pushState Leverages Url fragments
Default Must be set with { useHash: true }
More natural Url
Requires Url rewriting

Browser Server
www.mysite.com/APM/welcome APM/index.html
- APM
index.html - index.html
Browser Url Styles

HTML 5 Style (…/welcome) Hash-based (…/#/welcome)


Leverages HTML 5 history pushState Leverages Url fragments
Default Must be set with { useHash: true }
More natural Url Does not require Url rewriting
Requires Url rewriting

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

Define the base path


<base href="/">

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

Add the RouterOutlet directive


- Identifies where to display the routed
component's template
- Primary RouterOutlet normally specified
in the App component's template

<router-outlet></router-outlet>
Basics Checklist: Activating a Route

Add the RouterLink directive as an


attribute
- Clickable element
- Enclose in square brackets

Bind to a link parameters array


- First element is the root Url segment
- All other elements are route parameters
or additional Url segments
<a [routerLink]="['/welcome']">Home</a>
Setting up Routing
Summary - Defining the Base Path
- Importing RouterModule
- Configuring Application Routes
- Placing the Template (RouterOutlet)
- Activating Routes (RouterLink)

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
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 List Page Not Found


Component Component

Product Detail
Login Component
Component
Imports
Exports
Product Edit
Declarations Message Component
Component
Providers
Bootstrap
BrowserModule RouterModule
Feature Modules
HttpModule ...

App Module Product User Module Message


Module Module
Product List
App Component Login Component Message Component
Component

Welcome Product Detail


Component Component

Page Not Found Product Edit


Component Component

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

this.router.navigate('/welcome'); // Short-cut syntax

this.router.navigateByUrl('/welcome'); // Complete Url path

http://localhost:3000/products(popup:messages) // current route

http://localhost:3000/welcome(popup:messages) // navigate()

http://localhost:3000/welcome // navigateByUrl()
Demo

Activating a Route with Code


Matching Routes
app.module.ts Route Paths
imports: [
BrowserModule,
HttpModule, welcome
RouterModule.forRoot([
{ path: 'welcome',
''
component: WelcomeComponent },
{ path: '', redirectTo: 'welcome',
**
pathMatch: 'full' }, products
{ path: '**',
component: PageNotFoundComponent } login
]),
ProductModule,
UserModule,
MessageModule
]
Matching Routes
app.module.ts Route Paths
imports: [
BrowserModule,
HttpModule, products
RouterModule.forRoot([
{ path: 'welcome',
login
component: WelcomeComponent },
{ path: '', redirectTo: 'welcome',
welcome
pathMatch: 'full' }, ''
{ path: '**',
component: PageNotFoundComponent } **
]),
ProductModule,
UserModule,
MessageModule
]
Why Define a Routing Module?

• 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()

Configure the routes


Order matters!
@NgModule({
imports: [
...,
RouterModule.forChild([ { path: 'products',
component: ProductListComponent } ])
], ...
})
Routing to Features Checklist: Naming Routes

Use a common root path name for related


feature routes
- products
- products/:id
- products/:id/edit
Routing to Features Checklist: Activate with Code

Import the Router


Add a dependency on the Router service
- As a constructor parameter

Use the Router service navigate method


Pass in a link parameters array
- First element is the root Url segment
- All other elements are route parameters
or additional Url segments
this.router.navigate(['/welcome']);

this.router.navigateByUrl('/welcome');
Routing to Features Checklist: Routing Modules

Separate out routes to their own routing


module
Keep route path order in mind
Summary 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

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

<a [routerLink]="['/products', product.id]">{{product.productName}}</a>

<a [routerLink]="['/products', product.id, 'edit']">Edit</a>

<a [routerLink]="['/products', 0, 'edit']">Add Product</a>


<a routerLink="/products/0/edit">Add Product</a>

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'));
}

import { ActivatedRoute } from '@angular/router';


...
constructor(private route: ActivatedRoute) {
this.route.paramMap.subscribe(
params => {
console.log(params.get('id'));
}
);
}
With Required
Parameters
March 1, 2015

[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

[routerLink]="['/products', {name: productName, code: productCode,


startDate: availabilityStart, endDate: availabilityEnd}]"

http://localhost:3000/products;name=Controller;code=gmg;
startDate=March%201%2C%202015;endDate=March%201%2C%202017

{ path: 'products', component: ProductListComponent },


Reading Optional Route Parameters
Component Class
import { ActivatedRoute } from '@angular/router';
...
constructor(private route: ActivatedRoute) {
console.log(this.route.snapshot.params['name']);
console.log(this.route.snapshot.params['code']);
}

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

{ path: 'products', component: ProductListComponent }


Retaining Query Parameters
Template
<a [routerLink] = "['/products']"
[preserveQueryParams] = "true">
Back
</a>

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';

constructor(private route: ActivatedRoute) {


console.log(this.route.snapshot.queryParams['filterBy']);
console.log(this.route.snapshot.queryParams['showImage']);
}

Template
<a [routerLink] = "['/products', product.id]"
[queryParams] = "{ filterBy: listFilter, showImage: showImage }">
{{product.productName}}
</a>
Route Parameters Checklist: Required Parameters

Pass needed data on a route


Example:
- Detail component requires an id
Required Parameters
Configure
{ path: 'products/:id', component: ProductDetailComponent }

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

Pass optional or complex information to a


route
Example:
- Search component passes search
criteria to the List component to filter
the data
Optional Parameters
Not Configured
{ path: 'products', component: ProductListComponent }
Populate
<a [routerLink]="['/products',
{start: startDate, end: endDate}]">...</a>

this.router.navigate(['/products',
{start: startDate, end: endDate}]);
Read
this.route.snapshot.params['start'];
Or Observable
Route Parameters Checklist: Query Parameters

Pass optional or complex information to a


route that is optionally retained across
routes
Example:
- List component passes its current user
selections to the Detail component
which passes them back
Query Parameters
Not Configured
{ path: 'products', component: ProductListComponent }
Populate
<a [routerLink]="['/products']"
[queryParams]="{filterBy: 'x', showImage: true}">...</a>

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

Prevents display of a partial page


Reuses code
Improves flow when an error occurs
Module Providing Data with a Route

Overview Using a Route Resolver


Building a Route Resolver Service
Adding a Resolver to a Route
Configuration
Reading Resolver Data - Snapshot
Reading Resolver Data - Observable
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

Primary Routes
Secondary Routes
Child Routes
Providing Data with a Route

Amount of data Scope of data sharing How data is used


Providing Data with a Route

Optional
Route Query
Route
Parameters Parameters
Parameters

Route's Data Route Angular


Property Resolver Service
Route's Data Property
Angular Module
@NgModule({
imports: [
RouterModule.forChild([
{
path: 'products',
component: ProductListComponent,
data: { pageTitle: 'Product List' }
},
{ path: 'products/:id', component: ProductDetailComponent },
{ path: 'products/:id/edit', component: ProductEditComponent }
])
], ...

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

Build and register a route resolver service

Add resolve to the route configuration

Read the data from ActivatedRoute


Use a Snapshot
Use an Observable
Building a Route Resolver Service
product-resolver.service.ts
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from
'@angular/router';
import { Observable } from 'rxjs/Observable';

import { IProduct } from './product';

@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;

constructor(private route: ActivatedRoute) {


this.product = this.route.snapshot.data['product'];
}

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

Create an Angular service


Implement the Resolve<> interface
Add a resolve method
Be sure to register the service
export class ProductResolver implements Resolve<IProduct> { }

resolve(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<IProduct> { }
Route Resolvers Checklist: Configuring

Configure using resolve


Give each type of data a logical name
Specify a reference to the route resolver
{
path: 'products/:id',
component: ProductDetailComponent,
resolve: { product: ProductResolver }
}
Route Resolvers Checklist: Reading

Read the data from the route


- Snapshot

this.product = this.route.snapshot.data['product'];

- Data Observable
this.route.data.subscribe(
data => this.product = data['product'];
);
Providing Data with a Route

Summary Using a Route Resolver


Building a Route Resolver Service
Adding a Resolver to a Route
Configuration
Reading Resolver Data - Snapshot
Reading Resolver Data - Observable
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

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

Edit Info Edit Tags


Module Using Child Routes
Overview 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
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

Edit Info Edit Tags


Configuring Child Routes
Angular Module
{
path: 'products/:id/edit',
component: ProductEditComponent,
resolve: { product: ProductResolver },
children: [
{
path: '', redirectTo: 'info', pathMatch: 'full'
},
{
path: 'info', component: ProductEditInfoComponent
},
{
path: 'tags', component: ProductEditTagsComponent
}
]
}
Placing the Child View
product-edit.component.html
<div class="panel-body">
<div class="wizard">
<a [routerLink]="['info']">
Basic Information
</a>
<a [routerLink]="['tags']">
Search Tags
</a>
</div>

<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);
•@
•@

Child Route Resolver


•@
this.product = this.route.snapshot.data['product'];
•@
•@
•@

Parent Route Resolver


•@
this.product = this.route.parent.snapshot.data['product'];
•@
•@
•@
App
<router-outlet>
welcome products products/:id/edit products/:id

Product
Welcome Product List Product Edit
Detail
<router-outlet>
info tags

Edit Info Edit Tags


Validating Across Child Routes
Product Edit
<form>
Define the form in the parent <router-outlet>
component? </form>

Define a form in each child


component? Edit Info Edit Tags
<input> <input>
... ...
Define all of the tab elements in one </input> </input>
component?
Define a form in each child
component, but perform manual
validation?
Validating Across Child Routes
Product Edit
<router-outlet>
Define the form in the parent
component?

Define a form in each child


component? Edit Info Edit Tags
<form> <form>
<input> <input>
Define all of the tab elements in one ... ...
component? </input> </input>
</form </form
Define a form in each child
component, but perform manual
validation?
Validating Across Child Routes

Define the form in the parent Product Edit


component?

Define a form in each child


component?

Define all of the tab elements in one


component?
Define a form in each child
component, but perform manual
validation?
Validating Across Child Routes
Product Edit
<router-outlet>
Define the form in the parent
component?

Define a form in each child


component? Edit Info Edit Tags
<form> <form>
<input> <input>
Define all of the tab elements in one ... ...
component? </input> </input>
</form </form
Define a form in each child
component, but perform manual
validation?
Child Routes: Configuring

Add a children array to the parent route


Define the child routes within that array
Child paths extend the parent route
{
path: 'products/:id/edit',
component: ProductEditComponent,
resolve: { product: ProductResolver },
children: [
{ path: 'info', component: ProductEditInfoComponent },
{ path: 'tags', component: ProductEditTagsComponent }
]
}
Child Routes: Placing

Place the child view by defining a


RouterOutlet directive in the parent
component's template
<div class="panel-body">
<div class="wizard">
<a [routerLink]="['info']">Info</a>
<a [routerLink]="['tags']">Tags</a>
</div>

<router-outlet></router-outlet>
</div>
Child Routes: Activating

Using an absolute path


- Start with a slash
- Define each Url segment

Using a relative path


- No starting slash
- Only the child Url segment

<a [routerLink]="['/products', product.id, 'edit', 'info']">Info</a>


<a [routerLink]="['info']">Info</a>

this.router.navigate(['/products', this.product.id, 'edit', 'info']);


this.router.navigate(['info'], { relativeTo: this.route });
Child Routes: Obtaining Data

Read the data from the route


- Snapshot

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

Edit Info Edit Tags


Why?

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

<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
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

<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
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

<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
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

<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
Styling the Selected Route
Styling the Selected Route
Template

<a [routerLink]="['info']" routerLinkActive="active">


Basic Information
</a>
Animating Route Transitions

CSS Animation Angular Animation


Quick and easy More complex
Define some CSS Configure the animation
Every route in every component is Apply it to every component
animated!
May be getting better
Not truly animating our routes
Routing Events

NavigationStart RoutesRecognized NavigationEnd

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

this.router.events.subscribe((routerEvent: Event) => {


if (routerEvent instanceof NavigationStart) {
...
}
});
Routes: Styling

Style the active route using the


routerLinkActive directive
Style the correct element
For an exact path match use
routerLinkActiveOptions
<a [routerLink]="['info']" routerLinkActive="active">
Basic Information
</a>

<li routerLinkActive="active" [routerLinkActiveOptions]="{exact:true}">


...
</li>
Routes: Animating

Use CSS animation


Use Angular animation
Routes: Watching Events

Enable tracing to watch routing events in


the console
Add enableTracing to the route
configuration
imports: [
RouterModule.forRoot([
{ path: 'welcome', component: WelcomeComponent },
...
], { enableTracing: true })
],
...
Routes: Reacting to Events

Subscribe to the Router's events


observable
Check the event type as needed
this.router.events.subscribe((routerEvent: Event) => {
if (routerEvent instanceof NavigationStart) {
...
}
});
Summary Styled the Selected Route
Animated Route Transitions
Watched Routing Events
Reacted to Routing Events
App
<empty> <router-outlet> (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
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

<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
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 name="details"> <router-outlet name="images">

Details page here Images displayed here

</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 products login (popup:summary) (popup:messages)

Welcome Log In
Product
Message
<empty> :id/edit :id Summary

Product Product Product


List Edit Detail
<router-outlet>
info tags

Edit Info Edit Tags


Activating Secondary Routes: Router Link
Template

<a [routerLink]="[{ outlets: { popup: ['messages'] } }]">Messages</a>

<a [routerLink]="['/products', product.id, 'edit',


{ outlets: { popup: ['summary', product.id] } }]">Messages</a>
Activating Secondary Routes: In Code
Component Class
this.router.navigate([{ outlets: { popup: ['messages'] } }]);

this.router.navigate(['/products', product.id, 'edit',


{ outlets: { popup: ['summary', product.id] } }]);

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

<a [routerLink]="[{ outlets: { popup: null } }]">x</a>

Component Class

this.router.navigate([{ outlets: { popup: null } }]);

this.router.navigateByUrl('/login');
Secondary Routes: Named RouterOutlet

Add another RouterOutlet within a


template
Set its name attribute to a unique name
<div class="container">
<router-outlet></router-outlet>

<router-outlet name='popup'></router-outlet>
</div>
Secondary Routes: Configuring

Add the outlet property


Set it to the name of the associated
RouterOutlet
RouterModule.forChild([
{
path: 'messages',
component: MessageComponent,
outlet: 'popup'
},
])
Secondary Routes: Activating

Activate a secondary route using an object


and setting its outlets property
- Key: Outlet name
- Value: Link parameters array

<a [routerLink]="[{ outlets: { popup: ['messages'] } }]">Messages</a>

this.router.navigate([{ outlets: { popup: ['messages'] } }]);


Secondary Routes: Clearing

Clear a secondary route using an object


and setting its outlets property
- Key: Outlet name
- Value: null

<a [routerLink]="[{ outlets: { popup: null } }]">Messages</a>

this.router.navigate([{ outlets: { popup: null } }]);


Summary Using Secondary Routes
Defined a Named RouterOutlet
Configured a Secondary Route
Activated a Secondary Route
Cleared Secondary Outlet
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
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

Limit access to a route Warn before leaving a Retrieve data before


route accessing a route
Guard Processing

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

Checks criteria before activating a route


Commonly used to:
- Limit route access to specific users
- Ensure prerequisites are met

Called when the Url changes to the route


Sharing Data
Route canActivate(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
parameters console.log(route.params['id']);
...
}

Route data canActivate(route: ActivatedRouteSnapshot,


state: RouterStateSnapshot): boolean {
console.log(route.data['product']); // undefined
...
}

Service export class AuthService {


currentUser: IUser;
property redirectUrl: string;
}
canActivateChild Guard
Checks criteria before activating a child
route
Commonly used to:
- Limit access to child routes
- Ensure prerequisites for child routes are
met
Called when the Url changes to the child
route
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
canDeactivate Guard

Checks criteria before leaving a route


Commonly used to:
- Check for unsaved changes
- Confirm leaving an incomplete operation

Called when the Url changes to a different


route
Route Guards Checklist: Building

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

URL Request (www.mysite.com)

index.html
Response

App Files
Web
Web Browser Server

URL Request (www.mysite.com)

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

Use a feature module

Routes grouped under a single parent

Not imported in another module


Lazy Loading
app-routing.module.ts
RouterModule.forRoot([
...
{
path: 'products',
loadChildren: 'app/products/product.module#ProductModule'
},
...
])
canLoad Guard

Checks criteria before loading an


asynchronous route
Commonly used to:
- Prevent loading a route if a user cannot
access it
Preloading Feature Modules
Lazy Loading

Navigate Download
Download
Launch Template to a lazy lazy Template
imported
application appears loaded loaded appears
modules
feature module

Preloading (Eager Lazy Loading)

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 {

preload(route: Route, load: Function): Observable<any> {


...
}
}
Registering and Enabling a Strategy
app-routing.module.ts
...
import { SelectiveStrategy } from './selective-strategy.service';

@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

Use a feature module


Group routes under a single parent
Don't import feature module
Lazy Loading Checklist: Configuring

Add the loadChildren property


Set it to:
- The full path to the module
- A hash
- And the module's class name

{
path: 'products',
loadChildren: 'app/products/product.module#ProductModule'
}
Lazy Loading Checklist: Preloading

Preload all modules with


PreloadAllModules
Or build a custom preloading strategy
service
RouterModule.forRoot([
{
path: 'products',
loadChildren: 'app/products/product.module#ProductModule'
},
...
], { preloadingStrategy: PreloadAllModules })
Summary 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
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

<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
App
<empty> <router-outlet>
welcome login products **

Page Not
Welcome Log In
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
App <router-outlet
<empty> <router-outlet> name="popup">
welcome login products ** (popup: 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
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
App <router-outlet
<empty> <router-outlet> name="popup">
welcome login products ** (popup: 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
Checklist

Steps and tips


Revisit as you build
Learning More

Pluralsight Angular Courses


- "Angular 2: Getting Started"
- "Angular 2: First Look"
- "Angular 2: Fundamentals"

Book
- "Angular Router" by Victor Savkin
• https://leanpub.com/router
@deborahkurata

You might also like