Resolve Guard In Angular

Introduction

Angular provide resolve guard which is used to resolve data before navigation. It is used to ensure that we have specific data before we load a particular route. Angular provides a resolve interface in the @angular/router module. In some cases, if we don't get data from the server there is no point in navigating to a new route. In this case, we will use the Resolve interface to resolve the data before navigation itself. Using resolve, we can preload some data before route navigation.

Implementing Resolve Guard

We will create one service which will implement the Resolve interface which we need to import from the @angular/router module. This service will have @Injectable with it to use it in our application. We will define the method Resolve function in our service to implement the interface. The Resolve interface will either return a synchronous value or an asynchronous value. Asynchronous values are a promise or an observable. 

interface Resolve <T>{
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable <T> | Promise <T> | T
}
  • This interface will decide whether we can navigate to the new route or not. To implement this interface, we have to define one method resolve() which has two parameters.
  • The two parameters are the route as ActivatedRouteSnapshot and the state as RouterStateSnapshot
  • These arguments are provided by Angular when we will activate this guard before navigating to a route.
  •  The resolve returns either observable or promise.
  • The resolve interface is defined in the @angular/router module.
We will declare a service AlarmEditResolver which will implement the Resolve interface. Here our method is returning a promise. We are going to edit an alarm page. Before navigation, if we have data for the existing alarm id then only we will navigate to the alarm edit page. Otherwise, we need to navigate the user on the alarm list page only. The alarmService has getAlarmById() method and returns a promise. We will not able to load the new rote until this data is fetched from the service. If this method returns empty or null, we will get back to the alarm list page instead of the alarm edit page. 

export class AlarmEditResolver implements Resolve {
  constructor(private alarmService: alarmService, private router: Router) { }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise{
    let alarmId = this.route.snapshot.paramMap.get('id');
       
    return this.alarmService.getAlarmById(alarmId).then(res=> {
      if (res) {
        return res;
      } else {
        this.router.navigate(['/alarmList']);
        return null;
      }
    });
  }
} 

We have to define the above resolve in the route configuration using resolve property.


@Injectable()
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AlarmComponent } from './components/alarm/alarm.component';
import { AlarmCreateComponent } from './components/alarm-create/alarm-create.component';
import { AlarmHistoryComponent } from './components/alarm-history/alarm-history.component';
import { AlarmListComonent } from './components/alarm-list/alarm-list.component';

const routes: Routes = [
  { path: '', component: AlarmComponent },
  { path: ':id/alarm-history', component: AlarmHistoryComponent },
  { path: 'alarmlist', component: AlarmListComonent},
  { path: 'create-alarm', component: AlarmCreateComponent },
  { path: ':id', component: AlarmCreateComponent, resolve: { alarmEdit : AlarmEditResolver }
 }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class AlarmsRoutingModule { }

We have to define the AlarmEditResolver in the provider array of @NgModule decorator.

@NgModule({
   providers: [ AlarmEditResolver ],
})
export class AlarmsModule { } 

Comments