Mark
Mark

Reputation: 2587

Angular 5 Observable need to wait until it's comlpete

I need to wait until the getPermissions() observable is complete before calling the checkPermissions() method. But for the life of me I can't get it...

I've tried using async/await too but that doesn't seem to work for me either?

I need to have my permissions, before I can check them, right. Thoughts?

If there's a better way, I'm all ears.

Much appreciated.

import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable()
export class RoleGuardService implements CanActivate {
  
  constructor(public auth: AuthService,public router: Router) { }

  canActivate(route: ActivatedRouteSnapshot): boolean {
    //This will be passed from the route config, on the data property
    const expectedRole = route.data.expectedRole;
    var hasPerm = this.loadAndCheckPermissions(expectedRole);

    console.log('done! ' + hasPerm);
    return hasPerm;
  }

  loadAndCheckPermissions(expectedRole) {
    var hasPermission = false;
    localStorage.clear();
    var myPermissions = localStorage.getItem('user-permissions');
    
    if (myPermissions === null) {
      console.log("PERMISSIONS from Server!");

      //You can't wait for an Observable or Promise to complete.
      //You can only subscribe to it to get notified when it completes or emits an event.
      this.auth.getPermissions()
        .subscribe(res => {
          localStorage.setItem('user-permissions', JSON.stringify(res.body));

          //Check permissions now
          //hasPermission = this.checkPermissions(expectedRole);
        });
    } else {
      hasPermission = this.checkPermissions(expectedRole); 
    }

    console.log('loadAndCheckPermissions ' + hasPermission);
    return hasPermission;
  }

  //Check a permission here
  checkPermissions(expectedRole) {
    return this.auth.checkPermission(expectedRole);
  }
}

Upvotes: 0

Views: 2070

Answers (1)

Rodrigo
Rodrigo

Reputation: 2503

You can return a Observable in you canActivate method, like that:

import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable()
export class RoleGuardService implements CanActivate {

  constructor(
    public auth: AuthService,
    public router: Router
  ) { }

  canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {

    //This will be passed from the route config, on the data property
    const expectedRole = route.data.expectedRole;

    var hasPerm = this.loadAndCheckPermissions(expectedRole);

    console.log('done! ' + hasPerm);
    return hasPerm;
  }

  loadAndCheckPermissions(expectedRole):  Observable<boolean> {

    var hasPermission: Observable<boolean> = Observable.of(false);

    //clear
    localStorage.clear();

    //getter
    var myPermissions = localStorage.getItem('user-permissions');
    //
    if (myPermissions === null) {

      console.log("PERMISSIONS from Server!");

       hasPermission = this.auth.getPermissions()
        .map(res => {
          localStorage.setItem('user-permissions', JSON.stringify(res.body));
          console.log('return from async');

          // Check permissions RETURNING A BOOLEAN
          return this.checkPermissions(expectedRole);
        });

    }
    else {
      hasPermission = Obsersable.of(this.checkPermissions(expectedRole)); 
    }

   // console.log('loadAndCheckPermissions ' + hasPermission);
    return hasPermission;
  }

  //Check a permission here
  checkPermissions(expectedRole) {
    return this.auth.checkPermission(expectedRole);
  }


}

Accordingly to documentation of Angular, a routing guard can return an Observable or a Promise and the router will wait for the observable to resolve to true or false.

https://angular.io/guide/router#milestone-5-route-guards

Upvotes: 1

Related Questions