Angular 7 Guard redirection only works on double click

独自空忆成欢 提交于 2021-02-11 12:41:21

问题


THe problem is that I've implemented a Guard, meant to work with a specific directory . It should return true if the role of the current username equals 2 . If it doesn't then it shouldnt redirect.

THis is my app-routing-module.ts file , the problem is in the 'userlist' path, were we implement the [RoleGuard] canActivate

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Routes, RouterModule, Router } from '@angular/router';

import { PokemonListComponent } from '../../src/app/pokemon-list/pokemon-list.component';
import {LoginComponent} from '../../src/app/login/login.component'
import { AuthGuard } from './auth.guard';
import { RoleGuard} from './role.guard'

import {UserListComponent} from './pokemon-list/user-list/user-list.component'


const routes: Routes = [
  {path: 'pokemonlist', component: PokemonListComponent , canActivate: [AuthGuard]},
  {path: 'login', component: LoginComponent},
  {path: '',redirectTo: '/login',pathMatch: 'full'},
  {path: 'userlist', component: UserListComponent , canActivate : [ RoleGuard]} //this is the guard we are looking at
]

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    RouterModule.forRoot(routes)
  ],
  exports:[RouterModule]
})
export class AppRoutingModule { }

And this is my current role.guard.ts

     import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router';
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore';
import { Router } from '@angular/router';
@Injectable({
  providedIn: 'root'
})
export class RoleGuard implements CanActivate {
  data2 //variable to store the role of the current user , (1 or 2) . If its 2 the canActivate should return true.

  constructor(public db: AngularFirestore, private myRoute: Router) {
    //role extraction 
    //We get the role by comparing the uid , and store it in the "data2" var
    var docRef = this.db.collection('users').doc(localStorage.getItem('user'));

    docRef.get().toPromise().then(doc => {
      if (doc.exists) {
        this.data2 = doc.data().role;
      }
    });


  }

  canActivate() {
    //if data2 is 2, means that the redirection should work
    if ( localStorage.getItem('user') && this.data2 == 2 ) {  
        return true;
    } else {
      return false;
    }


  }

}

My navbard component where the click occurs , onUsersClick function

        import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/auth';
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore';
import { Router } from '@angular/router';
import {AuthService} from '../services/auth.service'
@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
  @Output() featureSelected = new EventEmitter<string>();

  myName;

  fullUser: any;
  name: string;
  constructor(public firebase: AngularFireAuth, public db: AngularFirestore, public router: Router,  private _authS: AuthService) {
    let userID = localStorage.getItem('user')
    this.myName= localStorage.getItem('displayName');

    //retrieve logged user data

    let docRef = db.collection('users').doc(userID);


    docRef.get().toPromise().then(doc => {
      if (doc.exists) {
        this.fullUser = doc.data();
      } else {
        console.log("No such document!");
      }
    }).catch(function (error) {
      console.log("Error getting document:", error);
    });



  }

  ngOnInit() {
  }

  onUsersClick() {
    this.router.navigate(['/userlist']);
  }

  onPokemonClick(feature: string) {
    this.router.navigate(['/pokemonlist']);
  }

  onSignOut() {
    localStorage.clear();
  }



}

My navbar html

    <!--navbar-->
<nav class="navbar navbar-expand-lg navbar-dark">
  <a class="navbar-brand" href="#">Pokedex</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
    aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="navbarSupportedContent">
    <ul class="navbar-nav mr-auto">

      <li class="nav-item active">
        <a class="nav-link" (click)="onPokemonClick()">Pokemons <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item active">
        <a class="nav-link" *ngIf="fullUser.role == 2" (click)="onUsersClick()">Users <span
            class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item active">
        <a class="nav-link" (click)="onSignOut()"href="#">Sign Out <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item active" *ngIf="myName != 'null'">
          <a class="nav-link" [ngStyle]="{'color': 'yellow'}">Welcome {{ myName }} !! <span class="sr-only">(current)</span></a>
      </li>



    </ul>

  </div>
</nav>

回答1:


Try with:

@Injectable({
  providedIn: 'root'
})
export class RoleGuard implements CanActivate {
  constructor(public db: AngularFirestore) {
  }

   async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean>  {
    if (localStorage.getItem('user') ) {  
       const doc = await this.db.collection('users')
                 .doc(localStorage.getItem('user'))
                 .get()
                 .toPromise();
       return doc.exists && doc.data().role === 2 ? true : false;
    } else {
      return false;
    }
  }
}

The issue might be related to the fact that you resolve a promise in your constructor and expect the result to be available at the moment that canActivate is invoked.



来源:https://stackoverflow.com/questions/55627562/angular-7-guard-redirection-only-works-on-double-click

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!