Friday, December 29, 2017

How do I create a CanDeactivate guard with conditional logic in an Angular 4 application?

Let's answer the question I posed yesterday here. To do so we are going to make an actual file for our guard and thus the provider in the outermost module may be removed and the reference to 'WhateverGuard' in the routing module should just become WhateverGuard without the surrounding quotes.

import { Injectable, Injector } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { WhateverGuardInterface } from './whatever-guard.interface';
import { StupidService } from '../../services/stupid-service';
@Injectable()
export class WhateverGuard implements CanDeactivate<WhateverGuardInterface> {
   private service:StupidService;
   
   constructor(public injector: Injector){
      this.service = injector.get(StupidService);
   }
   
   canDeactivate(component: WhateverGuardInterface, currentRoute:
         ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?:
         RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
      if(this.service.isToUseGuard){
         return confirm('Are you sure you want to leave?');
      } else {
         return true;
      }
   }
}

 
 

Alright, we are going to need a middleman service that will manage some sort of state to drive the conditional logic seen above. Assuming I have a component, WhateverComponent if you like, wherein there is a form to edit a record and I only want to ask "Are you sure you want to leave?" if one is midstream into editing a record, perhaps the dirty flag on the whole of the form would just serve nicely to drive our conditional logic. That Boolean value needs to unfortunately be communicated into a middleman service (write whatever gunk you need, that is not this lesson) and then the middleman service may also be talked to by our guard. My service is this simple:

import {Injectable} from '@angular/core';
@Injectable()
export class StupidService {
   public isToUseGuard: boolean;
}

 
 

A setting for component at the canDeactivate method is unfortunately mandatory as is some sort of type at the class signature in a shape that reminds one of C# generics. I looked into TypeScript generics some and I guess they are comparable. Anyhow, I don't really understand what to do with this yet and as I turns out I don't have to. I just made a super simple interface to satisfy this requirement that looks like this:

export interface WhateverGuardInterface {}

 
 

What else am I not mentioning? Loop the service and the guard in at Providers in the outermost module! The guard has to be an import at the routing module when you take away the quotes around WhateverGuard as suggested at the very top of this blog posting.

No comments:

Post a Comment