What is Angular Router?
An Angular Router is a tool, library that configures navigations between states and views within your Angular app.
The Routing library is written and maintained by the Angular Core Team.
Angular router has own library package – @angular/router.
import {Routes, RouterModule,} from '@angular/router';
The basic concept of Angular Router and It allows you to:
- Redirect a URL to another URL
- Resolve data before a page is displayed
- Run scripts when a page is activated or deactivated
- Lazy load parts of our application
The router supports both styles with two LocationStrategy providers:
- PathLocationStrategy— this is the default style.
- HashLocationStrategy— adds the route path to the hash (#) in the browser’s URL.
What is Router module?
The Router module is a module that provides the necessary service providers and directives for navigating one view to other in the application.
What is Routes?
Angular Route is an array of route configurations. The “RouterModule.forRoot” method in the module imports to configure the router.
type Routes = Route[];
Each Route has the following properties:
interface Route {
path?: string
pathMatch?: string
matcher?: UrlMatcher
component?: Type<any>
redirectTo?: string
outlet?: string
canActivate?: any[]
canActivateChild?: any[]
canDeactivate?: any[]
canLoad?: any[]
data?: Data
resolve?: ResolveData
children?: Routes
loadChildren?: LoadChildren
runGuardsAndResolvers?: RunGuardsAndResolvers
}
List of properties and it has the following order:
- path – It uses the route matcher DSL
- pathMatch – It uses to specifies the matching strategy
- matcher – It uses to defines a custom strategy for path matching
- component – It is a component type
- redirectTo – It is the URL fragment and it will replace the current matched segment
- outlet – It is the name of the outlet the component should be placed into
- canActivate – It is an array of DI tokens and used to handle the CanActivate handlers
- canActivateChild – It is an array of DI tokens and used to handle the CanActivateChild handlers
- canDeactivate – It is an array of DI tokens and used to handle the CanDeactivate handlers
- canLoad – It is an array of DI tokens and used to handle the CanLoad handlers
- data – It is additional data provided to the component by using the ActivatedRoute
- resolve – It is a map of DI tokens used to look up data resolvers
- runGuardsAndResolvers – It is defined when guards and resolvers will be run and by default, they run only when the matrix parameters of the route change.
- children – it is an array of child route definitions
- loadChildren – It is a reference to lazily loaded child routes.
The following example help you to understand the Router, Router module, and Routes.
In this example, the array of appRoots describes how to navigate from one view to other views and pass it into RouterModule.forRoot method to configure the router.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {Routes, RouterModule,} from '@angular/router';
//Import Components
import { AppComponent } from './app.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { UserComponent } from './user/user.component';
import { UserDetailComponent } from './user-detail/user-detail.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component'
//Apps roots
const appRoots = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'user/:id', component: UserDetailComponent }, //Id is a Roots parameter.
{ path: 'users', component: UserComponent, data:{ title:'User List'} },
{ path: '**', redirectTo: 'PageNotFoundComponent' } //Wild Cards (**), the router will instantiate the PageNotFound component
];
//AppModule class with @NgModule decorator
@NgModule({
//Static, this is the compiler configuration
//declarations is used for configure the selectors
declarations: [
AppComponent,
DashboardComponent,
UserComponent,
UserDetailComponent,
PageNotFoundComponent,
],
//Composability and Grouping
//imports used for composing NgModules together
imports: [
BrowserModule,
//enableTracing is used for debugging purposes only
RouterModule.forRoot(appRoots, { enableTracing: true })
],
//Runtime or injector configuration
//providers is used for runtime injector configuration
providers: [],
//bootstrapped entry component
bootstrap: [AppComponent]
})
export class AppModule { }
How Angular Router Works?
Angular Router performs the following steps in order:
- The router reads the browser URL the user wants to navigate to
- The router applies a URL redirect (if one is defined otherwise page not found the error)
- It figures out which router state corresponds to the URL
- It runs the guards that are defined in the router state
- It resolves the required data for the router state
- It activates the Angular components to display the page
- It manages navigations and repeats the steps above when a new page is requested.
Angular Router introduces the following terms and concepts:
- <base href>
- Router imports
- Configuration
- Router outlet
- Router links
- Router state
- Activated route
- Router events
What Is <base href>?
Most of all Angular routing apps must have the <base> element to the index.html or layout page in the <head> tag.
When using the PathLocationStrategy, need to tell the browsers what will be prefixed to the requested path to generate the URL.
You can specify a base URL like this :
<base href="/">
Or:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Demo Apps</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
So if you had an Angular route defined like this:
{ path: 'users', component: UserComponent, data:{ title:'User List'} }
If <base href=”/” >, the route become “/users”.
If <base href=”/angular” >, the route become “/angular/users”.
How to Append Base URL to HTTP requests?
We can append base URL to HTTP requests using:
- Dependency Injection
- Using HttpInterceptors
The following example for append base URL using DI -Firstly, we register a base URL provider in the NgModule and after register this BASE_URL, it is available universally in your Apps.
//Runtime or injector configuration
//providers is used for runtime injector configuration.
providers: [{ provide: 'BASE_URL', useFactory: getBaseUrl }],
Now provide factory method which gets the base URL from <base> element.
export function getBaseUrl() {
return document.getElementsByTagName('base')[0].href;
}
Finally, we can get the base URL injected and add it to URL:
export class GetUserComponent {
constructor(http: Http, @Inject('BASE_URL') baseUrl: string) {
http.get(baseUrl + 'api/users').subscribe(data => {
this.users = data.json();
}, error => console.error(error));
}
}
The following example for append base URL using HttpInterceptors
If we wants to create an interceptor, we must create an Injectable class which implements HttpInterceptor.
Firstly, register interceptor in the module provider:
//Runtime or injector configuration
//providers is used for runtime injector configuration.
providers: [{ provide: HTTP_INTERCEPTORS, useClass: ApiInterceptor, multi: true } ],
And after register interceptor, to create:
@Injectable()
export class ApiInterceptor implements HttpInterceptor {
//Intercepts HttpRequest and handles them.
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const baseUrl = document.getElementsByTagName('base')[0].href;
const apiReq = req.clone({ url: `${baseUrl}${req.url}` });
return next.handle(apiReq);
}
}
Now we can access the base URL in your across apps.
What Is PathLocationStrategy?
A LocationStrategy used to configure the Location service that represents its state in the path of the browser’s URL and the PathLocationStrategy is a default routing strategy.
When you are using the PathLocationStrategy, we must provide APP_BASE_HREF in the module or base element in the app document.
What Is HashLocationStrategy?
To enable HashLocationStrategy in an Angular app you pass {useHash: true} when you providing routes with router module and it like this.
//Composability and Grouping
//imports used for composing modules together.
imports: [
BrowserModule,
//enableTracing enables debugging purposes only
//useHash enables the location strategy that uses the URL fragment instead of the history API.
RouterModule.forRoot(appRoots, { enableTracing: true, useHash:true })
],
The HashLocationStrategy add the route path to the hash (#) in the browser’s URL.
The hash (#) part of the URL is called the hash fragment.
When using HashLocationStrategy for routing and providing a base Href, it always placed after the hash (#) e.g.
http://localhost:8080/#/UserDetail/1
The Hash style routing using the anchor tags technique to achieve client side routing and URL never sent to the server.
The anchor tag, when used along with the hash (#) allows us to jump to a place, within apps.
The URL would look like this
1. http://localhost:8080
2. http://localhost:8080/#/Users
3. http://localhost:8080/#/UserDetail/1
In the above URLs “#/Users” and “#/UserDetail/1” never sent to the server.
How do you change the base URL dynamically?
Instead of setting the base element’s href value, you can set the base URL programmatically, by providing for APP_BASE_HREF with your custom operation.
What Is Router imports?
It is an optional service that presents a special component view for a given URL. It has own library package- @angular/router and It is not a part of an Angular core.
The Angular package looks like this:
import {Routes, RouterModule,} from '@angular/router';
How to configure Angular routes?
A router has no routes until you configure it. So you are configuring the Angular router for accessing your apps URLs.
//Composability and Grouping
//imports used for composing NgModules together.
imports: [
BrowserModule,
//enableTracing is used for debugging purposes only
//Enables the location strategy that uses the URL fragment instead of the history API.
RouterModule.forRoot(appRoots, { enableTracing: true, useHash:false })
]
For the detail, you can refer Angular Routes example for the same.
What Is Router outlet?
The Router-Link, RouterLink-Active and the Router outlet is directive provided by the Angular RouterModule package. It’s provides the navigation and URLs manipulation capabilities. It also renders the components for specific location of your applications.
Both the template and templateUrl render the components where you use this directive.
<router-outlet> </router-outlet>
Is it possible to have a multiple router-outlet in the same template?
Yes, why not! We can use multiple router-outlets in the same template by configuring our routers and simply adds the router-outlet name.
<div class="row">
<div class="user">
<router-outlet name="users"></router-outlet>
</div>
<div class="detail">
<router-outlet name="userDetail"></router-outlet>
</div>
</div>
And setups your route config and it looks like this:
//Apps roots
const appRoots = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'userDetail', component: UserDetailComponent }, //Id is a Roots parameter.
{ path: 'users', component: UserComponent, data:{ title:'User List'} },
{ path: '**', redirectTo: 'PageNotFoundComponent' } //Wild Cards, the router will instantiate the PageNotFound component.
];
And:
//AppModule class with @NgModule decorator
@NgModule({
//Composability and Grouping
//imports used for composing NgModules together
imports: [
BrowserModule,
//enableTracing is used for debugging purposes only
//Enables the location strategy that uses the URL fragment instead of the history API.
RouterModule.forRoot(appRoots)
],
//bootstrapped entry component
bootstrap: [AppComponent]
})
export class AppModule { }
What Is Router link?
The Router-link is a directive and it used to link a specific part of your applications.
@Directive({ selector: ':not(a)[routerLink]' })
Let explain the route configuration using the
{ path: 'user/:id', component: UserDetailComponent
In the above rote configuration, when linking to this user/:id route, you use the RouterLink directive.
If the link is static, you can use the directive as follows.
<a routerLink="/user/id"> See the User detail</a>
If you using dynamic values to generate the router link that you can pass an array of path segments.
You can specify a route parameter like this.
<a [routerLink]="['/user', user.id]">
<span class="text-align">{{ user.id }}</span>{{ user.name }}
</a>
You can set query params and fragment as follows:
<a [routerLink]="['/user/id']" preserveQueryParams preserveFragment>
See the user component
</a>
You can specify optional route parameters like this:
<a [routerLink]="['/user-detail', { id: '102348014' }]">User Detail</a>
And:
@Component({
selector: 'app-user',
template: `<nav>
<a [routerLink]="['/users']">User List</a>
<a [routerLink]="['/userDetail/101', { Id: '102348014' }]">User Detail</a>
</nav>
<router-outlet></router-outlet>`,
styleUrls: ['./user.component.css']
})
What Is RouterLinkActive?
The RouterLinkActive is a directive. To add the active CSS class to the element when the associated RouterLink becomes active (visually look like selected anchors). It is also works for both parent and child elements.
@Directive({
selector: '[routerLinkActive]',
exportAs: 'routerLinkActive'
})
Consider the following example for active a link:
<a routerLink="/user/detail" routerLinkActive="active-link">User Detail</a>
You can also set more than one class and it look like this:
<a routerLink="/user/detail" routerLinkActive="active-class1 active-class2">User detail</a>
<a routerLink="/user/detail" [routerLinkActive]="['active-class1', 'active-class2']">User detail</a>
What Is RouterState?
RouterState is interface and it represents the state of the router.
It looks like this.
It is also a tree of activated routes.
We can access the current RouterState from anywhere in the Angular app using the Router service and the routerState property.
What Is ActivatedRoute?
ActivatedRoute is an interface and it contains the information about a route associated with a component loaded into an outlet and it can also be used to traverse the router state tree.
- And it contains the list of Properties:
- Snapshot – It is the current snapshot of this route.
- URL – It is an observable of the URL segments and it matched by this route
- Params – It is an observable of the matrix parameters scoped to this route
- QueryParams – it is an observable of the query parameters shared by all the routes
- Fragment- It is an observable of the URL fragment shared by all the routes
- Data- It is an observable of the static and resolved data of this route.
- Outlet. It’s a constant and outlet name of the route
- Component- It’s a constant and a component of the route
- RouteConfig- This configuration used to match this route
- Root- This is the root of the router state
- Parent – The parent of this route in the router state tree
- FirstChild- The first child of this route in the router state tree
- Children- The children of this route in the router state tree
- pathFromRoot- The path from the root of the router state tree to this route
- paramMap- It is read-only
- queryParamMap- It is read-only
What are Router events?
Whenever the root navigations, the router emits navigation events using Router.events property.
- The sequence of router events is:
- NavigationStart
- RouteConfigLoadStart
- RouteConfigLoadEnd
- RoutesRecognized
- GuardsCheckStart
- ChildActivationStart
- ActivationStart
- GuardsCheckEnd
- ResolveStart
- ResolveEnd
- ActivationEnd
- ChildActivationEnd
- NavigationEnd
- NavigationCancel
- NavigationError
The Router events are also logged in the console when enableTracing option is enabled.
The NavigationStart event is triggered when navigation starts.
The RoutesRecognized event triggered when the routes are recognized.
The RouteConfigLoadStart event triggered before the Router lazy loads.
The RouteConfigLoadEnd event triggered after a route has been lazily loaded.
The NavigationEnd event triggered when navigation ends successfully.
The NavigationCancel event triggered when navigation is canceled.
The NavigationError event triggered when router navigation fails due to an error.