简体   繁体   中英

canActivate not working when url is typed

Basically everything works correctly until for some reason when the url is typed the variable this.estado within the method canActivate happens to be undefined.

I think that this because the constructor does not get the observable at the correct time.

 import { Component, Injectable, Inject, OnInit } from '@angular/core'; import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/catch'; import 'rxjs/add/observable/throw'; @Injectable() export class AuthService implements CanActivate { myAppUrl: string; estado: any; constructor(private router: Router, private http: HttpClient, @Inject('BASE_URL') private baseUrl: string) { this.myAppUrl = baseUrl; this.estadoSetUp(); /* If I put hear this.estado = true everything works fine */ } public getJSON(): Observable<any> { return this.http.get(this.myAppUrl + 'api/IsAuthenticated'); } public estadoSetUp() { this.getJSON().subscribe(data => { this.estado = data.AmILoggin; }); } canActivate(): Observable<boolean> { if (this.estado != true) { this.router.navigate(['/']); } return this.estado; } } 

SOLVED thanks to @sirdieter

I leave here the solution for anyone having trouble in the future:

 import { Component, Injectable, Inject, OnInit } from '@angular/core'; import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { ReplaySubject } from 'rxjs/ReplaySubject' import 'rxjs/add/operator/map'; import 'rxjs/add/operator/catch'; import 'rxjs/add/observable/throw'; import 'rxjs/add/operator/do'; @Injectable() export class AuthService implements CanActivate { myAppUrl: string; private isAuthorized = new ReplaySubject<boolean>(1); constructor(private router: Router, private http: HttpClient, @Inject('BASE_URL') private baseUrl: string) { this.myAppUrl = baseUrl; this.estadoSetUp(); } public getJSON(): Observable<any> { return this.http.get(this.myAppUrl + 'api/IsAuthenticated'); } public estadoSetUp() { this.getJSON().subscribe(data => { this.isAuthorized.next(data.AmILoggin); }); } canActivate(): Observable<boolean> { return this.isAuthorized.asObservable() .do(auth => { if (auth != true) { this.router.navigate(['/']); } }); } } 

Be aware that your http call is async,

Therefor, when you open an URL directly, this guard is constructed (it starts the http call), AND very soon after that (milliseconds) the "canActivate" is called. As a result, if your http call wasn´t fast enough, your variable isn´t defined, because there are no results from the http call.

canActivate returns an Observable of a boolean. So one solution would be to change your variable estado to an observable

You correctly found out the problem. You can return the http call observable and map it to the AmILoggin property. (RxJS 6 Syntax, you seem to have 5)

canActivate(): Observable<boolean> {
    return this.getJSON().pipe(pluck('AmILoggin');
}

But in this case you would make the http call everytime canActivate() is called; To only have one http call you could use a Subject:

private isAuthorized = new ReplaySubject<boolean>(1);

public estadoSetup() {
    this.getJSON().subscribe(data => this.isAuthorized.next(data.AmILoggin));
}
// RxJS 6
canActivate() {
    return this.isAuthorized.asObservable().pipe(
      tap(auth => {
        if (auth) {
            this.router.navigate(['/']);
        }
      }
    );
}
// RxJS 5
canActivate(): Observable<boolean>
    return this.isAuthorized.asObservable()
    .do(auth => {
        if (auth) {
            this.router.navigate(['/']);
        }
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM