skip to Main Content

I have two services which returns Observables one is admin service which checks if user is admin and the second one is the service with method fetching CVs to see if user has already created cv. I want to lock /new page if user has already created cv and have it enabled all the time when user is an admin or manager no matter what 🙂 My guard stops to work when user is an admin and has CV created at other cases it works fine. I work on Angular 11 and rxjs 6.6.3

import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Observable, combineLatest, zip } from 'rxjs';
import { PersonsService } from '../services/persons.service';
import { finalize, map, take, tap } from 'rxjs/operators';
import { AdministrationService } from '../services/administration.service';
import { CustomSnackbarService } from '../services/custom-snackbar.service';

@Injectable({
  providedIn: 'root',
})
export class CanCreateNewCv implements CanActivate {
  constructor(
    private usersService: PersonsService,
    private router: Router,
    private administrationService: AdministrationService,
    private snackbarService: CustomSnackbarService
  ) {}

  canActivate(): Observable<boolean> | boolean | Promise<boolean> {
    let isAllowed = false;
    const cv$ = this.usersService.getPersonsByPageAndFilter(10, 0).pipe(
      map((data) => {
        if (data.allDataCount > 0) {
          this.router.navigateByUrl('/list');
          return true;
        }
        return false;
      })
    );

    const admin$ = this.administrationService.getCurrentUser().pipe(
      map((currentUser) => {
        if (currentUser.isAdmin || currentUser.isManager) {
          return true;
        }
        return false;
      })
    );

    return combineLatest([cv$, admin$], (isCvUploaded, isAdminOrManager) => {
      isAllowed = isAdminOrManager ? true : isCvUploaded ? false : true;
      return isAllowed;
    }).pipe(
      finalize(() => {
        if (!isAllowed)
          this.snackbarService.open(
            'This profile has CV already created!',
            'Info'
          );
      })
    );
  }
}

I tried zip opearator as well and it also doesn’t work

2

Answers


  1. It seems all good. combineLatest will complete only after all source observables complete, so only thing that comes to my mind is that one of your observables, cv$ or admin$, doesn’t complete in that specific case. But I don’t know how they’re build.
    What you can try is to add take(1) in both pipes, which will ensure that those observables will complete after emitting 1 value:

    const cv$ = this.usersService.getPersonsByPageAndFilter(10, 0).pipe(
      take(1),
      map((data) => {
        if (data.allDataCount > 0) {
          this.router.navigateByUrl('/list');
          return true;
        }
        return false;
      })
    );
    
    const admin$ = this.administrationService.getCurrentUser().pipe(
      take(1),
      map((currentUser) => {
        if (currentUser.isAdmin || currentUser.isManager) {
          return true;
        }
        return false;
      })
    );
    

    If that doesn’t work you can check if those observables emit value and complete by adding some console.log in combineLatest block.

    Login or Signup to reply.
  2. It’s not working because you are redirecting him not matter if he is your superuser or not.

    It should be:

    export class CanCreateNewCv implements CanActivate {
      constructor(
        private usersService: PersonsService,
        private router: Router,
        private administrationService: AdministrationService,
        private snackbarService: CustomSnackbarService
      ) {}
    
      canActivate(): Observable<boolean> | boolean | Promise<boolean> {
        let isAllowed = false;
        const cv$ = this.usersService
           .getPersonsByPageAndFilter(10, 0)
           .pipe(
              map((data) => data.allDataCount > 0)
           );
    
        const admin$ = this.administrationService
           .getCurrentUser()
           .pipe(
              map((currentUser) => currentUser.isAdmin || currentUser.isManager)
           );
    
        return combineLatest([cv$, admin$], (isCvUploaded, isAdminOrManager) => {
          isAllowed = isAdminOrManager ? true : isCvUploaded ? false : true;
          if (!isAllowed) {
            this.router.navigateByUrl('/list');
          }
          return isAllowed;
        }).pipe(
          finalize(() => {
            if (!isAllowed)
              this.snackbarService.open(
                'This profile has CV already created!',
                'Info'
              );
          })
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search