I am working on a following code:
import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from '@angular/router';
import {Observable} from 'rxjs';
import {AngularFireAuth} from '@angular/fire/auth';
import {map, tap} from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class ChatGuard implements CanActivate {
constructor(private afAuth: AngularFireAuth,
private router: Router) {
}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable <boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.afAuth.authState
.pipe(
map(user => user !== null),
tap(value => {
if (!value) {
this.router.navigateByUrl('/login').then();
return value;
} else {
return value;
}
})
);
}
}
Versions i have are:
Angular CLI: 13.1.4
Node: 16.14.0
I have this error in this part of code:
return this.afAuth.authState
.pipe(
map(user => user !== null),
tap(value => {
if (!value) {
this.router.navigateByUrl('/login').then();
return value;
} else {
return value;
}
})
Saying:
Type 'Observable<unknown>' is not assignable to type 'boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree>'.Type 'Observable<unknown>' is not assignable to type 'Observable<boolean | UrlTree>'.Types of property 'source' are incompatible.
Do you know how I can solve this?
CodePudding user response:
Type 'Observable' is not assignable to type 'Observable<boolean | UrlTree>
your return type is of observable while in the method signature you defined return type to be Observable <boolean | UrlTree>
a possible solution is to check what this.afAuth.authState
return and update it's signature to return Observable<boolean | UrlTree>
CodePudding user response:
According to the documentation, the tap operator is "A function that returns an Observable identical to the source, but runs the specified Observer or callback(s) for each item".
Which means you don't have to return value
in a tap. It will be done by default.
In the other hand, you don't want to redirect the route after returning the boolean value, you need to do it before.
So i suggest you to change your code into this :
return this.afAuth.authState
.pipe(
map(user => {
const isLogged = !!user;
if(!isLogged){
this.router.navigateByUrl('/login')
return false;
} else {
return true
}
})
);
Also it might happen that on a page refresh (F5), the this.afAuth.authState
emits first a null
value right before the user
object.
That would gives you a rejection whereas the user is logged.
In that case I suggest you to add a debounceTime operator before the map.