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.

What is Angular Resolver?

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.

General Routing Flow v/s Angular Resolver Routing Flow

This section might help you to differentiate between the routing flow with or without resolvers.

General Routing Flow v/s Angular Resolver Routing Flow

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.

Why Choose Angular Resolvers?

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.

Resolve Interface

Let’s see how the Resolve Interface looks before building our demo.

Copy Text
export interface Resolve<T> {
  resolve(
   route: ActivatedRouteSnapshot, 
   state: RouterStateSnapshot
  ): Observable<T> | Promise<T> | 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:

  • Route- ActivatedRouteSnapshot
  • State- RouterStateSnapshot

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:

  • Observable
  • Promise
  • Custom type

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.

Angular Resolver Example: How to Implement?

Follow the instructions step by step to build the Angular Resolver example with me.

1) Create a new Angular app

Create a new Angular application by executing the below command:

Copy Text
ng new AngularResolver 

2) Create components

Create a components folder having three components – Home, Products, About.

Copy Text
ng g c components/home
ng g c components/about
ng g c components/products

3) Fetching data

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

Copy Text
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<Product[]> {
    return this.http.get<Product[]>(this.url);
  }
}

4) Product Interface

Create the Product interface having the following structure.

// product.ts

Copy Text
export interface Product {
  id: string;
  image: string;
  title: string;
  price: string;
  description: string;
}

5) Implement the Resolve method

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

Copy Text
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<any> {
  constructor(private product: ProductService) {}
  resolve(route: ActivatedRouteSnapshot): Observable<any> {
    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.

6) Route Configuration

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

Copy Text
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.,

Copy Text
 resolve: { products: ProductsResolverService }

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.

7) Access the Resolved Data

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

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

8) Display the data

To display the data, use the following code in the products.component.html file.

// products.component.html

Copy Text
<div class="wrapper">
  <div *ngFor="let product of products" class="card">
    <img [src]="product.image"/>
    <div>
      <h3>{{product.title}}</h3>
      <p class="price">Price = ${{product.price}}</p>
      <p>{{product.description}}</p>
    </div>
    <div class="cart-btn-div">
      <button type ="button">Add to Cart</button>
    </div>
  </div>
</div>

9) Add a Loading Spinner

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

Copy Text
<style>
  .content {
    display: flex;
    margin: 82px auto 32px;
    flex-direction: column;
    align-items: center;
  }
  .card-container {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    margin-top: 16px;
  }
  .card {
    border: 1px solid #eee;
    background-color: #fafafa;
    height: 40px;
    width: 200px;
    margin: 0 8px 16px;
    padding: 16px;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  a,
  a:visited,
  a:hover {
    color: #1976d2;
    text-decoration: none;
  }
  a:hover {
    color: #125699;
  }
  }
</style>
<div *ngIf="loading" id="myModal" class="modal">
  <div class="lds-roller">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
</div>
<div class="content" role="main">
  <div class="card-container">
    <a class="card" routerLink="/home">
      <span>Home</span>
    </a>
    <a class="card" routerLink="/products">
      <span>Products</span>
    </a>
    <a class="card" routerLink="/about">
      <span>About</span>
    </a>
  </div>
</div>
<router-outlet></router-outlet>

// app.component.ts

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

Output: Angular Resolver Example

Here’s a video of the output of the Angular Resolver Example.

Conclusion

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.

Hire AngularJS Developer

Start 15 Days Free Trial

Get In Touch

[email protected]

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