July 17, 2020

Resolver In Angular

Why do we need Resolver?

Suppose you are building an awesome app where you load fetch, update, insert, and delete data from backend off course through the API services. Many times, we need to pass the data between two routes, or it may be the case that our 'Y' component needs data that is loaded by the 'X' component. In simple words, you have a cake shop app and you want to load all the cakes from the backend or from some other component. In all the above scenarios, if you have not made any special adjustment for data loading, you will face error/warning in the browser, as shown below.

In the above case, I have cakeStockID as a defined property in Model.

The reason behind this is it doesn't get the data before rendering the HTML. i.e. our HTML loads before fetching data from the back end.

This situation can be eliminated in different ways, but we have a Resolve interface provided by angular.

So to handle this situation we will wait for the data to be load and then proceed further. Let's do it by the resolver.

To get in-Depth knowledge on Angular you can enroll for a live demo on Angular Online Training

Our steps will be:

Create a Resolver ====> give that resolver object while routing ====> fetch loaded data via resolver in constructor of consuming constructor.

My scenario: I want to load all the cakes from the backend via resolver.

Step 1

Let's create a standalone component for the resolver, as shown below:

import {  
    Injectable  
} from '@angular/core';  
import {  
    Resolve,  
    ActivatedRouteSnapshot,  
    RouterStateSnapshot  
} from '@angular/router';  
import {  
    showcaseCakesModel  
} from '../rollin-shared/showcase-cakes.model';  
import {  
    rollinDataStorageService  
} from '../Services/rollin-datastorage';  
import {  
    Observable  
} from 'rxjs'  
@Injectable({  
    providedIn: 'root'  
})  
export class dataResolverService implements Resolve < showcaseCakesModel[] > {  
    constructor(private svcObj: rollinDataStorageService) {}  
    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable < showcaseCakesModel[] > | showcaseCakesModel[] {  
        return this.svcObj.get();  
    }  
}  

svcObject is my service object from where I am fetching the data.

So here, we are calling our get method. Ultimately, we want this data to be loaded as soon as we load the component.

Step 2

There is a way to tell Angular, 'Hey buddy! I want to load this data first via resolver whenever the 'XYZ' component is loaded.' For that, we need to mention this resolver name as a parameter in routing, as shown below.

In my scenario: I want to load all the cakes from backend via resolver in ViewAllCakeComponent.

import { dataResolverService } from './rollin-cakes/data-resolver';  
  
const rollinRoute: Routes=[    
    {path:'',component:RollinAppComponent,pathMatch:'full',resolve:{data:dataResolverService}},    
    {path:'view-allcakes',component:ViewAllcakesComponent,pathMatch:'full',resolve:{data:dataResolverService}}    
 ]    

Here, we are giving 'data' as a key to retrieve the loaded data by the resolver. You can give it any other name also.

Take your career to new heights of success with Angular Training

Step 3

So, all good until now! Let's use this in our component where we want to load data before anything. To do that, we need to inject this resolver in the component.

In the constructor, it self-retrieves data loaded by the resolver from ActivatedRoute, as shown below.

This is quite relatable. If you look at resolve interface carefully, you will find its first parameter is ActivtedRouterSnapshot..

import { Component, OnInit, DoCheck } from '@angular/core';    
import { cakesTransactionService } from '../cake-transactions';    
import { showcaseCakesModel } from 'src/app/rollin-shared/showcase-cakes.model';    
import { rollinDataStorageService } from 'src/app/Services/rollin-datastorage';    
import { Router, ActivatedRoute } from '@angular/router';    
    
@Component({    
  selector: 'app-view-allcakes',    
  templateUrl: './view-allcakes.component.html',    
  styleUrls: ['./view-allcakes.component.css']    
})    
export class ViewAllcakesComponent implements OnInit {    
  displayCakes:showcaseCakesModel[];    
    
  constructor(private route:Router,    
              private actRoute:ActivatedRoute,     
              private cakeObj:rollinDataStorageService,    
              private cakeTransactionServiceObj:cakesTransactionService) {     
    //console.log("called Constructor")    
    
    this.displayCakes= this.actRoute.snapshot.data['data'];    
    
    //console.log( this.displayCakes);    
  }      
  ngOnInit(): void {  
  }      
}   

It's done! Now going forwards, whenever this component is called, this data will be ready for us!