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.

Table of Contents

Introduction

Are you tired of watching your Angular app struggle to load data, leaving users impatiently tapping their fingers? We’ve all been there—waiting for screens to settle, feeling frustrated by sluggish performance. However, there’s a robust solution to this challenge- Angular Resolver

In this blog tutorial, we’ll explore Angular resolvers and learn how they can optimize data fetching in Angular applications with extensive examples. To understand it better, we will also cover the difference between general routing and resolvers in Angular routing flow.

What is Angular Resolver?

Angular Resolver is used to pre-fetch data when the user navigates from one route to another. It can be defined as a smooth approach to enhancing user experience by loading data before the user navigates to a particular component.

Let’s understand the reasons for choosing resolver in Angular and what benefits it can provide to your application.

Angular Resolver Example

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

In this case, we might face an issue as the component will be ready before receiving the data (the array item isn’t yet with us).

Here comes Route Resolver to the rescue. We can use Angular’s Route Resolve class to fetch the data before your component is loaded. Then, the conditional statements can work smoothly with the Resolver.

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

You must note that steps 2, 3, and 4 are done with the help of resolvers. So, we can conclude that the resolver Angular is an intermediate code executed between clicking the link and loading the component.

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.

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;
      }
    });
  }
}

However, if you are still struggling with resolver, you can partner with Angular consulting services providers for insightful advice and strategic guidance.

You can get more such spinner templates from loading.io. Moreover, the entire source code of the Resolver Angular example is available on the Github repository.

Conclusion

So, this was about implementing Route Resolver in Angular. It is a robust mechanism that enhances user experience by fetching essential data before the user navigates to a particular component. You can even visit Angular Tutorials to explore and learning Angular.

At Bacancy, we have skilled and experienced Angular developers with fundamental and advanced knowledge. If you are looking for dedicated and enthusiastic developers, contact us to hire Angularjs developer for fulfilling your project requirements with the expertise.

Need Help to Implement Angular Resolver?

BOOK A FREE 30 MIN CALL

Build Your Agile Team

Hire Skilled Developer From Us

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

How Can We Help You?