Quick Summary:
We all know how the world of applications is progressing rapidly. Your application has to be up to date from user experience to app performance in such a competitive virtual world. Users will surely close your application if it takes time to load. Developing a real-time app with multiple server requests/calls can lead to a poor user experience if it’s not handled properly. You have to build the app keeping the user experiences in mind because your application can’t afford such negative impacts due to APIs.
Now, you might wonder how to handle multiple requests without affecting the user experience. One of the solutions to this issue is to implement Angular Resolver. Today, in this tutorial, we will learn the implementation of Route Resolvers in Angular.
Angular Resolver is used for pre-fetching some of the data when the user is navigating from one route to another. It can be defined as a smooth approach for enhancing user experience by loading data before the user navigates to a particular component.
Let’s see what the difference is in the routing flow if we implement resolvers.
This section might help you to differentiate between the routing flow with or without resolvers.
Steps 2,3 and 4 are done with the help of resolvers.
So we can conclude that resolver is an intermediate code that is executed between clicking the link and loading the component.
Angular Resolvers let the application fetch remote data from the server before the activatedRoute of the next component is activated. We don’t require a spinner until the data is fetched because we won’t be able to navigate to the next component unless the server data is retrieved.
To understand it better, let’s take one scenario- we want to display the array items in a component received in an unordered list or table. For that, suppose we have *ngIf=”some condition” and our business logic depends upon the length of an array, which will be altered once the API call is successful.
Struggling to build high-performance Angular applications?
Here we are to lessen your hustles! Contact one of the best Angular Development Company who will help you meet your project requirements efficiently with commendable problem-solving skills.
We might face an issue in such a case as the component will be ready before receiving the data (the array item isn’t yet with us).
Here comes Route Resolver to rescue. We can use Angular’s Route Resolver class for fetching the data before your component is loaded. And then, the conditional statements can work smoothly with the Resolver.
Let’s see how the Resolve Interface looks before building our demo.
export interface Resolve { resolve( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable | Promise | T { return 'Data resolved here...' } }
For creating a route resolver, you need to implement the above interface with your new class. The interface offers a resolve function which indeed gets two parameters:
You can make the API call of which you want to pre-fetch the data before the component renders. With the help of route parameters, you can have route parameters used in the API call.
A resolve method can return:
Keep in mind that only resolved data can be returned by this method. So, you have to complete them before sending them to the route.
I hope the theory so far was helpful for the starters. Let’s start some coding and develop our demo application.
Follow the instructions step by step to build the Angular Resolver example with me.
Create a new Angular application by executing the below command:
Create a components folder having three components – Home, Products, About.
Create a service with a file named product.service.ts to fetch the product’s data from the remote source. In this service, create a function called getProducts() that returns an observable containing data from an API.
// product.service.ts
import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Injectable } from '@angular/core'; import { Product } from '../../interfaces/product'; @Injectable({ providedIn: 'root' }) export class ProductService { url = 'https://fakestoreapi.com/products?limit=6'; constructor(public http: HttpClient) {} getProducts(): Observable { return this.http.get (this.url); } }
Create the Product interface having the following structure.
// product.ts
export interface Product { id: string; image: string; title: string; price: string; description: string; }
Create a products-resolver.service.ts file and implement the resolve method from the Resolve interface of the router for fetching server data as follows.
// products-resolver.service.ts
import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, Resolve } from '@angular/router'; import { Observable, of } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { ProductService } from '../product/product.service'; @Injectable({ providedIn: 'root' }) export class ProductsResolverService implements Resolve { constructor(private product: ProductService) {} resolve(route: ActivatedRouteSnapshot): Observable { console.log('Called Get Product in resolver...', route); return this.product.getProducts().pipe( catchError(error => { return of('No data'); }) ); } }
The ProductsResolverService class will automatically subscribe to the getProducts observable and provide the router with the fetched data. Only resolved data could be returned from the method.
Once we are done with the above steps, we need to configure our routes to specify the data needed to be prefetched for each component. For that, modify the routes in the app-routing.module.ts file.
// app-routing.module.ts
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AppComponent } from './app.component'; import { AboutComponent } from './components/about/about.component'; import { HomeComponent } from './components/home/home.component'; import { ProductsComponent } from './components/products/products.component'; import { ProductsResolverService } from './services/productsResolver/products-resolver.service'; const routes: Routes = [ { path: 'home', component: HomeComponent }, { path: 'products', component: ProductsComponent, resolve: { products: ProductsResolverService } }, { path: 'about', component: AboutComponent } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule {}
Within the routes, we provide a key “resolve” containing an object to be used for extracting the data, i.e.,
The “resolve” key is assigned with an object having “products” as a key and “ProductsResolverService” as its value, as you can see above. The data is passed to an object with a property named products.
The resolve() function of “ProductsResolverService” is invoked, and the returned Observable is resolved before the component is loaded. The data extracted from the API is assigned to the “products” object and can be accessed in the component.
For accessing the resolved data, we will use the data property of ActivatedRoute service. In the products.component.ts file, use the following code to access the data:
// products.component.ts
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Product } from '../../interfaces/product'; @Component({ selector: 'app-products', templateUrl: './products.component.html', styleUrls: ['./products.component.css'] }) export class ProductsComponent implements OnInit { products: Product[]; constructor(private activatedRoute: ActivatedRoute) {} ngOnInit(): void { console.log( 'Activated route data in Component:::', this.activatedRoute.data ); this.activatedRoute.data.subscribe((response: any) => { console.log('PRODUCT FETCHING', response); this.products = response.products; console.log('PRODUCT FETCHED'); }); } }
To display the data, use the following code in the products.component.html file.
// products.component.html
For a better experience, integrate the loading spinner, add the following code in the app.component.ts and app.component.html files.
// app.component.html
// app.component.ts
import { Component } from '@angular/core'; import { NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { loading = false; title = 'angu-res'; constructor(public router: Router) { this.router.events.subscribe(ev => { if (ev instanceof NavigationStart) { this.loading = true; } if ( ev instanceof NavigationEnd || ev instanceof NavigationCancel || ev instanceof NavigationError ) { this.loading = false; } }); } }
You can get more such spinner templates from loading.io.
The entire source code of the Angular Resolver example is available on the Github repository.
So, this was about implementing Route Resolver in Angular. I hope the purpose of the blog is served the way you’ve expected. Feel free to visit Angular Tutorials to explore and learning Angular.
At Bacancy, we have skilled and experienced Angular developers having fundamental and advanced knowledge. If you are looking for dedicated and enthusiastic developers, contact us to hire Angular developer. We assure to fulfill your project requirements with our expertise.
Navigating client's requirement with precision is what our developers' focuses on. Besides, we develop to innovate and deliver the best solutions to our clients.
get in touchYour Success Is Guaranteed !
We accelerate the release of digital product and guaranteed their success
We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.