In traditional web applications, when we want to move from one view to another, we generally send a request to the server and get a new page from the server. The browser will create a new URL for the requested view and send it to the server.
Modern web applications use modern frameworks such as Angular to overcome this issue. Angular project uses a different approach to move from one view to another. It contacts the server only once when bootstrapping and gets the main HTML file.
Any URL changes in our application will be handled by the router on the client side. This type of application is called a Single Page Application (SPA) which prevents pages from reloading.
Please refer to the image below for the SPA lifecycle
@angular/router is the JavaScript package that implements the angular router service and enables navigation from one component to another component. Due to RouterModule, we can create multiple views and navigate between them.
1. It allows us to create multiple router outlets.
2. It provides different path-matching strategies.
3. You get easy access to route parameters.
4. Route guards that prevent components/modules from unauthorized access.
Moreover, we need to import a routing module in our application to use the features of routing.
//angular router module
import { RouterModule } from '@angular/router';
Using the root component method, we import RouterModule in the main application routing module as it is an AppModule by default.
For the router outlet code please refer to below snippet:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
//Here we import array of routes defined in app routing module
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
NgbModule,
BrowserAnimationsModule,
],
providers: [],
exports : [],
bootstrap: [AppComponent]
})
export class AppModule { }
A router outlet is a directive available in the @angular/router library that specifies what content should be rendered on a web page. Based on the browser URL path component would be inserted into the <router-outlet/>.
Example of app routing module file:
import { NgModule } from '@angular/core';
// importing router module and routes
import { RouterModule, Routes } from '@angular/router';
// routes array
const routes: Routes = [
{path: 'home', component: HomeComponent},
{path: 'about', component: AboutComponent},
{path: 'contact', component: ContactComponent},
];
@NgModule({
imports: [RouterModule.forRoot(routes,{useHash:true})],
exports: [RouterModule]
})
export class AppRoutingModule { }
We want to insert the template associated with each route we need to add a router outlet directive.
<router-outlet></router-outlet>
In app.component.html, when we open localhost:4200/home it renders the content associated with the home component. If we go for localhost:4200/about or localhost:4200/contact, it renders content associated with about and contact components.
We can have multiple router outlets in our applications which is used to create more complex routing scenarios.
Angular router matching strategy defines which route should be activated when the user navigates to a URL path. Angular has 3 different route matching strategies prefix, full, and exact. Angular routing uses the first match wins strategy, which means that the first matched const routes view will be loaded.
Prefix: matches the URL prefix. This is the default route matching strategy in Angular.
Full: matches the full URL.
Exact: matches the exact path segment.
You can create a custom matching function using the pathMatcher interface.
The following example shows how to create a custom pathMatcher function
const matcher: Matcher = (url: UrlSegment[]) => {
if (url.length === 1 && url[0].path === 'home') {
return { consumed: url };
} else {
return null;
}
};
const route: Route = {
path: 'home',
pathMatch: matcher,
component: HomeComponent
};
Angular has three types of routes:
1. Static Route
2. Dynamic Route
3. Wildcard Route
An example of each type of route is shown below
Static routes are used when we want to open a particular view on a fixed route. In the above example, we have created a products route which is called when we provide a URL path as localhost:4200/products every time which uses a prefix router matching strategy by default.
Dynamic routes are used when we don't know the URL after a specific path. In the above example, ProductDetailsComponent is called whenever any value comes after "/products".
A Wildcard route is called when the requested URL does not match any path for defined routes. This type of wildcard route is generally used for showing "NotFound" or redirecting to another route.
Route guards are the interfaces that tell Angular routing whether or not it should allow navigation to a requested route. Route guards are looking for true or false return values from a class that implements a given guard interface.
It is fundamental in our application to have a login/logout scenario where users perform application tasks. By using the following route guards, we can easily manage which pages are allowed for logged-in users and not logged-in users.
There are 5 types of guards in Angular:
1. CanActivate
2. CanActivateChild
3. CanDeactivate
4. CanLoad
5. Resolve
CanActivate guard is used to protect routes from unauthorized users. For example, if a user is not logged in and trying to access a protected route then by using canActivate guard we prevent the user from accessing protected content. CanActivate guard decides this by using the true or false value from the class that implements this interface.
CanActivateChild route definition is very similar to the can activate guard. We can apply this guard on the parent so that before navigating to child routes we apply our logic. This guard also makes decisions using the true or false values from the class that implements this guard.
Example of CanActivateChild Guard:
{
path: 'product', component: ProductComponent,
canActivate : [AuthGuardService],
canActivateChild : [AdminGuardService],
children: [
{ path: 'view/:id', component: ProductViewComponent },
{ path: 'edit/:id', component: ProductEditComponent },
{ path: 'add', component: ProductAddComponent }
]
},
CanDeactivate guard is used to prevent the user from accidentally leaving the page. Suppose we have created a form and we want to prevent the user navigates from this page before it submits the form then we can deactivate the guard to do this.
import { CanDeactivate } from '@angular/router';
export class CanDeactivateGuard implements CanDeactivate {
canDeactivate(component: MyComponent, currentRoute: ActivatedRouteSnapshot) {
if (component.form.dirty) {
return confirm('You have unsaved changes. Are you sure you want to leave?');
}
return true;
}
}
// routes array
const routes: Routes = [
{
path: 'my-component',
component: MyComponent,
canDeactivate: [CanDeactivateGuard]
}
];
CanLoad guard is very similar to CanActivate guard but the main difference between canload and canActivate guard is that canload guard first checks the condition and then loads the module/component property but CanActivate first check load the module/component property and then checks the condition.
This guard also makes decisions using true or false values from the class that implements this interface.
const routes: Routes = [
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
canLoad: [AuthGuard]
},
{
// Empty Path
path : "",
patchMatch : "full",
redirectTo : "admin"
}
];
A resolve guard is used for pre-fetching the data. This guard checks the data that exists means you will be navigated on a requested route once you receive the data.
For example, suppose you have to navigate on a profile route and you want to navigate if the data is available then we can use this guard as it ensures that the data is available before navigation.
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
@Injectable()
export class ResolveGuardGuard implements Resolve<any> {
constructor(public service: DataServiceService ){}
resolve(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot){
return this.service.myPromisse().then(d => d);
}
}
const route : Routes = [
{
path:'about', component: AboutComponent , resolve: [ResolveGuardGuard]
}
];
Angular routing has a router link directive for navigating through creating routes. Router class having router.navigate and router.navigateByURL are two methods to navigate between various routes. They are as follows:
Traditional web applications use different pages to link. However, single-page applications don't use different pages instead they use a different view to display. To navigate users from different views angular uses router link directive instead of traditional href.
// Traditional HTML look like this which uses anchor tag for navigation
<a href="/test">
Test HTML link.
</a>
// Modified HTML after applied routerLink directive look like this
<a routerLink="/test">
Test HTML link.
</a>
Relative paths (“../”) are used to go to higher levels in the navigation.
In the above example suppose the user is at /setting/profile route and you want to go to /user/user-details this is possible using relative paths.
We can pass the parameters with navigation by using objects.
In the above example, the router will be navigated to /users;special=false/userId.
Angular provides a Router class from the “@angular/router” package, this class contains router.navigate and router.navigateByURL, these two methods for navigation. To use these two classes you have to first inject router class in your component class.
Router.navigate gets an array of URL segments to navigate.
Router.navigateByURL is similar to router.navigate but the main difference between these two is that navigate uses url segment array and navigateByUrl uses string and the path must be absolute and start with “/”.
An activated route is a route that is currently visited by the user or which is the current browser URL.
@angular/router manages these routes and gets information about the active route through an instance of ActivatedRoute. When a current URL is visited, angular renders the corresponding component and injects the ActivatedRoute instance into the component.
This ActivatedRoute instance contains information about the route parameters, query parameters, data, and other relevant details. By injecting the ActivatedRoute instance in your component from @angular/router you can access parameters or data passed through the route.
Example of how to use ActivatedRoute :
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent implements OnInit {
constructor(private route: ActivatedRoute) { }
ngOnInit(): void {
// Accessing route parameters
const id = this.route.snapshot.params['id'];
// Accessing query parameters
const param = this.route.snapshot.queryParams['param'];
// Accessing route data
const data = this.route.snapshot.data;
}
}
In the above example, this.route.snapshot.params are used to get or access the path parameters and this.route.snapshot.queryParams is used to get or access the query parameters as well as this.route.snapshot.data is used to access route data.
The ActivatedRoute in Angular provides three main properties to access different kinds of information about the current route: params, queryParams, and data.
The params property provides access to the path parameters.
Route parameters are placeholders in the route URL defined by the route's path. For example, in the route /users/:id, id is a route parameter.
You access route parameters using the params property of ActivatedRoute. For example, this.route.snapshot.params['id'] will give you the value of the id parameter in the current route.
// Accessing route parameters
const id = this.route.snapshot.params['id'];
The queryParams property provides access to the query parameters.
Query parameters are key-value pairs appended to the URL after the "?" character. For example, in the URL /search?q=angular, q is a query parameter.
You access query parameters using the queryParams property of ActivatedRoute. For example, this.route.snapshot.queryParams['q'] will give you the value of the q query parameter in the current route.
// Accessing query parameters
const param = this.route.snapshot.queryParams['param'];
The data property provides access to any static data associated with the route. Static data is data defined in the route configuration and remains constant for the route's lifetime. You access static data using the data property of ActivatedRoute. For example, this.route.snapshot.data will give you access to any static data defined for the current route.
In summary, params are for accessing route parameters, queryParams are for accessing query parameters, and data is for accessing static data associated with the route configuration. Each of these properties serves a different purpose in providing information about the current route in an Angular application.
// Accessing route data
const data = this.route.snapshot.data;
Lazy loading techniques can significantly improve your application performance. Lazy loading is nothing but on-demand loading in which resources are loaded only when it is required. Splitting your applications into small separate modules and loading them on demand will reduce the initial load time of your application and improve the performance.
To optimize the routing performance use these best practices:
1. Keep routes well organized and maintainable.
2. Don’t use a deeply nested route structure, it will create confusion.
3. Avoid multiple route guards and guards with heavy logic.
4. Use route resolvers for data fetching before navigation.
Angular routing, along with the ActivatedRoute and route guards, provides a powerful mechanism for navigating and protecting routes in Angular applications.
In summary, Angular routing combined with ActivatedRoute and route guards enables developers to create dynamic and secure navigation experiences in Angular applications, allowing fine-grained control over route access and behavior.
This website uses cookies to analyze website traffic and optimize your website experience. By continuing, you agree to our use of cookies as described in our Privacy Policy.