Resolvers in Angular 14+

In Angular, a Resolve Guard is used to pre-fetch data before navigating to a route. This is particularly useful when you need to ensure that necessary data is available before a component is instantiated.

By using a Resolve Guard, you can delay the navigation to a route until the required data has been retrieved, thereby avoiding issues such as empty states or component loading delays.

We will explore two approaches: using Resolve Guard and ngOninIt for data fetching.

Lets dive into Resolve Guard step by steps
1. Create Angular app using CLI command ng new resolve-guard-example.
2. Navigate to our created project folder using cmd command
cd new resolve-guard-example.**
3. And start our project using this command ng serve or npm start.
4. Once we done our initial project creation setup will create our Components, Service and Guard.

5. Refer this Link to generate component, service, guard and more.

https://www.digitalocean.com/community/tutorials/angular-angular-cli-reference

Creating Required files

data.service.ts
I have created a service file where the getUsers() method returns a promise with data.

The service file code snippet is attached below.

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { of } from 'rxjs/observable/of';
import { catchError, delay } from 'rxjs/operators';

@Injectable()
export class DataService {
  constructor(private http:HttpClient){}
  getUsers(): Observable<any> {
    return this.http.get('https://jsonplaceholder.typicode.com/users').pipe(
      delay(3000),
        catchError(error=>{
            return of([]);
        })
    );
  }
}

Here, I used delay operator to understand the concepts of resolve guard and I return an empty array to handle any errors or you can navigate to an error page instead of returning an empty array.”
Try this "https://jsonplaceholder.tpicode.com/users”** to get error***.***

resolve.guard.ts

We import the Resolve interface from @angular/router. We use this interface in our resolver, and the resolve method of our resolver returns the data.

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot, Resolve } from '@angular/router';
import { Observable } from 'rxjs';
import { DataService } from '../service/data.service';

@Injectable()
export class ResolveGuard implements Resolve<any> {
  constructor(private dataService: DataService) {}
  resolve(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<any> {
    return this.dataService.getUsers();
  }

demo.component.ts

Here, we simply log the data from the ActivatedRoute to the console, but you can handle it according to your needs. You can remove the comment line to better understand the minor differences between using a Resolve guard and ngOnInit for calling APIs."

import { DataService } from '../shared-module/service/data.service';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-about',
  templateUrl: './about.component.html',
  styleUrls: ['./about.component.css'],
})
export class AboutComponent implements OnInit {
  constructor(
      private activatedRoute:ActivatedRoute,
      private datService:DataService
 ) { }

  ngOnInit() {
    // this.datService.getUsers().subscribe((res)=>{
    //   console.log("res",res)
    // })
    console.log("Resolved data",this.activatedRoute.snapshot.data)
  }
}

app.routing.module.ts

And finally we will attach the Resolve Guard in our AppRoutingModule

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AboutComponent } from './about/about.component';
import {  ResolveGuard } from './shared-module/gaurd/resolve.guard';

const route : Routes = [
  {
     path:'', 
     component: AboutComponent,
     resolve:[ResolveGuard]
  }
]

@NgModule({
  imports: [RouterModule.forRoot(route)],
  declarations: [],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Error Handling

We handling errors in the service level is useful for dealing with network issues or API errors directly. And If the service is used in multiple places, handling errors in the service ensures that the error handling logic is centralized and consistent across the application.

Also we handles errors in guard level specific route handling allows for different error management strategies based on the route, such as displaying a specific error page or redirecting, offering flexibility in error handling. Additionally, if you need to control navigation based on errors, such as redirecting to an error page when data can’t be resolved, handling errors in the guard is appropriate for managing route navigation effectively.

That’s the end of it.

Comment your thoughts… :)

7
Subscribe to my newsletter

Read articles from Devanathan Janarthanan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Devanathan Janarthanan
Devanathan Janarthanan

Hi, I'm Dev, a Senior Software Engineer specializing in Angular and React, with a focus on responsive design, performance optimization, and advanced UI features.