All About Routing in Angular Application
Hello,
In this article of routing in the angular application, I will cover routing from scratch to details. I will start from how routing works in angular and then we will dive deeper with routing. Below are some use cases,
· How does routing work? (creating routing from scratch)
· How to deal with wildcard characters? ( Not Found Routes)
· How to display the current page as active on the menu bar? (routerLinkActive)
· How to Guard Routes? (canActivate)
· How to store redirectURL and navigate to the same URL after a successful login?
· Child Routing?
· How to display login and logout button conditionally?
· How to display a spinner/progress bar using routing? (resolver)
· How to make routing, case insensitive?
· Many more…
At the end of the article, you will have depth knowledge of Routing in the angular application.
So, as we will be focusing only on routing, we will not go in details with any other topics like how to fetch data through HTTP client and how to create services and all.
So, I had already created the project and directory structure which is shown below.
So, already I had created product, home, user and header component as shown in the directory structure. Now to start with we will see how routing works?
How does routing work?
I will divide the routing process into 4 steps.
1) Create the routes array
I will create a separate routing file and name it as app.routing.ts
so when we request http://localhost:4200/products, it will check for the path of “ products” in our routing array, and if it finds that particular path it will display the corresponding component accordingly.
I had created an array of routes and I have declared that array as a root route or parent route. And I am exporting the root route so that we can import it on app.module.ts file
2) Import routes array in app.module.ts
3) Create a separate header.component and replace href => routerLink
Here, I am using bootstrap 4 for styling purpose only. And to make routing work in an angular application we will be using routerLink directives instead of href.
So we can use it like:
<a class=”nav-link” routerLink=”/home”>Home </a>
“/home “ will be the same as we had declared in the routing file.
4) Use <router-outlet> on app.component.html
Now, replace the app.component.html as shown below,
First, it will display menu, i.e. header.component.html and then inside router-outlet it will display the component, which will match with the path, declared in routes array. Say for example if we request http://localhost:4200/ then as per routing array it will display the home.component.
How to deal with wildcard character?
Say, for example, the user will request a path/URL which doesn’t match with any path from routing array! we can handle this by simply updating our routes array as shown below,
Here, I have added only one path with “**” this stands for if your URL or path doesn’t match to any path defined in routing array then display page-not-found component. ( like error 404) but the most important thing, the order of path:’**’ must be last only, otherwise if you add ‘**’ path first in routing array then no other routes will work.
How to display current menu item selected on the menu bar?
Say, for example, if we are on the home page, then the currently selected menu item should be Home, and if we navigate to the Products page, then the currently selected menu item should be Products.
We can achieve it by simply writing CSS class for display the currently selected menu item highlighted and then apply that CSS class to your header component, I am using Bootstrap 4, so it comes with pre-built CSS classes, in my case “Active” class is already created, so I am just applying it to my header component as shown below,
We can also use [routerLinkActiveOptions]=”{ exact : true}”,
To match the exact path.
How to store redirectURL and navigate to the same URL after a successful login?
Now, to achieve above-said use case, I already have created user-auth service and login component as shown below,
user-auth.services.ts
To provide you with an overview of user-auth.service.ts, I had created a login and logout methods, which will validate the user, here I am using some static values, you can replace it with your actual values. I had created an isLoggedIn property to return a Boolean value, it will return true if the user is logged in and false if not logged in. Also, I have created two properties current user to store current user credentials and redirectURL to store the path from which user is redirected to the login page so that after successfully logged in we can navigate user back to actual URL.
login.component.html
login.component.ts
So, now here if the user is successfully validated, then we will also check for the redirectURL property of user-auth services, if it is empty then by default we will redirect the user to the product list page and if there is a value in the redirectURL property, we will redirect the user to the actual URL.
How to display login and logout button conditionally?
In order to display login and logout button conditionally i.e. if the user is logged in then display Logout button and if the user is not logged in then display Login button. To do so we need to update the header component as shown below,
Header.component.html
Header.component.ts
Here, I have created isLoggedIn which will return true or false based on user’s logged in status, and I am using isLoggedIn property on my template to display either Login button or Logout button based on the value returned by isLoggedIn.
How to Guard Routes? (canActivate, canLoad)
It is always required that not every user have access to all the routes, say for example we don’t want to allow any user to have access to products pages like products list page and add new products page without logging In. we can do it simply by creating a guard for that.
Now to achieve above-said use case, first I have created user-guard service as shown below,
Here in the above service, I have implemented CanActivate, CanLoad interface from angular/router package which will be used to protect our routes. Here we are checking the user’s logged-in status and based on that we are allowing the user to navigate to a particular page.
Also, update app.routing.ts file as shown below,
So as I said before the products list and add product pages should be displayed only after the user loggedIn,that can be taken care of by canActivate directive, so now when user requests for a particular page it will first check the credentials in auth-guard services inside canActiviate interface and then user will be allowed to visit a particular page.
Child Routes?
We can also manage routes using children property on routing array, say for example if we want to organize all routes related to the products under one parent object, we can define children inside the parent object as shown below,
So, now if we request for http://localhost:4200/products/, it will first go to products object and then inside products object, it will go to its children which is an array of child component and then check for matching the path to load the component. In our particular case, it will load the product list component.
Also, we need to update the header.component.html because we had changes routing array.
Now although I had requested for addproduct page, but it will first redirect me to log in because of user-guard service.
Now after a successful login by default, it should redirect me to the product list page, but in this case, it will redirect me to add product page because of the redirecURL property of user-auth service.
How to display spinner using routing event? (Resolver)
Well, we can display spinner in the angular application in various ways, but I am talking about displaying spinner using routing event. It will solve your two problems, one it will prevent to load the page partially and other it will also display a spinner.
How many time have you faced a problem, when you navigate to a page and you are making an HTTP call to fetch the data, and your template/ HTML is loaded and still you are waiting to load your HTTP data. i.e. because of partial page loading, angular manages to route locally so your HTML/template will be loaded, but still, you are waiting for HTTP calls to complete to display the data. As a solution to this, we can use one of the routing event, which will only load the page/navigate to page after your HTTP call completes, this way you can prevent to partial page loading and also able to display spinner.
Okay so first create product-resolver.service.ts, as shown below,
Here, I had implemented the Resolve method of the interface, which will return the productResolved Observable before navigating or loading the page. Below are the product and product resolved classes,
Here, Product class will describe what type of data we are receiving from HTTP call, and productResolved class is for holding the product data as well as errors if any.
Now in order to resolver make working we need to do some adjustment in app.routing.ts as shown below,
Now to display the spinner, we need to subscribe to the routing events on root component i.e. app.component.html, by subscribing to root component, we don’t need to put the spinner on each and every page, we just need to put the spinner on root component only, below is how app.component.ts will look like,
Here I am subscribing to routing events first and then checking for navigationStart and NavigationEnd, based on that I am updating the loading property to true or false, which will be used on HTML/template to display the spinner. Below is a snippet of app.component.html,
So, now when I request, http://localhost:4200/products first it will navigate us to the login page, remember we had used user-guard service, then after login, it will first call resolver service to fetch the data, and then only it will navigate to the product list page, below is code snippet of product-list.component.ts,
So, now on product list.component.ts instead of making an HTTP call, we will just use the data which is already been fetched by resolver services,
this.data=this._router.snapshot.data[“productData”];
here “prodcutData” is the same name which we had used while declaring the app.routing.ts,
After routes get resolved it will display the product list page.
How to make routing, case insensitive?
The routes in the angular application are case sensitive, i.e. if you have defined
{path: ‘home’, component: HomeComponent},
And if you request http://localhost:4200/home, it will work fine, but it will not work with following routes,
http://localhost:4200/hoME, etc
so to make all above URL work in angular application, I found a common workaround and i.e. UrlSerializer, we can create lowecaseurlserializer which is derived from defaulturlserializer as shown below,
Which will simply convert all URLs to lowercase so that it will match our routing array. Now in order to make this lowecaseurlserializer to work, we need to make an adjustment to app.module.ts as shown below,
Download:
node js application for back end only
script for products table
CREATE TABLE IF NOT EXISTS `products` (
`p_id` int(11) NOT NULL AUTO_INCREMENT,
`pname` varchar(50) NOT NULL,
`pprice` int(11) NOT NULL,
`pimg` varchar(200) NOT NULL,
`soh` int(11) NOT NULL,
PRIMARY KEY (`p_id`)
)