I am doing a guard in Angular 7 to verify if a user is logged in or not. Both the back and the request work correctly, however I can't control it inside the subscribe. This is the code I developed
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { LoginService } from '../login.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { StorageService } from '../storage.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor( private _login: LoginService,
private _router: Router,
private _session: StorageService) {}
canActivate(): Observable<boolean> | boolean {
this._login.isLogged()
.subscribe(
// Si la respuesta es un código HTTP 204, entonces está autorizado
() => true,
// Si la respuesta es un código HTTP 401 entonces NO está autorizado
() => {
this._session.deleteData();
this._router.navigate(['/login']);
return false;
});
}
}
The problem is that return
del .subscribe
doesn't return true or false as canActivate(): Observable<boolean> | boolean
I don't know how to return that Boolean
I get this error
A function whose declared type is neither 'void' nor 'any' must return a value.
I even tried to assign the value of subscribe
to a variable to do return
at the end of canActivate()
, however it is an asynchronous function so it finishes executing the code and does not wait for the response, I reiterate, everything works excellent, both the responses from the backend, and the function isLogged()
which returns the Observable
one I am subscribing to in the guard.
What I can do?
I also tried this function
return this._login.isLogged().pipe( map( (data: any) => {
if( data.auth ) {
return true;
} else {
this._session.deleteData();
this._router.navigate(['/login']);
return false;
}
})
)
And now it works only if there is an HTTP 200, I can't control the 401 code
You should not use
subscribe
inside a guard because what it needs is aObservable
as such and what calling this function returns is aSubscription
which is the one that contains the methodunsubscribe
and so that the guard internally can register the emission of values what it needs is be able to access the same onesubscribe
that is included in the interface of theObservable
.You can use the operator
map
to transform the value you receive when executing your functionisLogged()
and return one of the values that guards can process . Ideally these values should betrue
if access is allowed or anUrlTree
if it is not. For example:They
UrlTree
are supported as of Angular >= 7.1 , can be easily created with the functioncreateUrlTree
, and are used as a better alternative to typingnavigate
accompanied byreturn false
. For example these codes inside a guard are equivalent :a
If you use a version lower than 7.1 you will have to use the first alternative but in no case should you just return false without navigating because the user will not know that an error has occurred.
Here I leave a more detailed explanation of the operators
equals
Whatever the result, if the http status code is in the range of the
200
guard will receive a valuetrue
and proceed to navigate to the requested routeIf the result status code is you
>=400
call the methoddeleteData
and return an observable usingof
that will produce a static value and then complete. This static value isUrlTree
what the guard expects to know where it should go.You can use the map operator to return, for example
Adding the
return
and usingpipe
got you going in the right direction, but you missed handling errors, it looks like you removed that part of the code:You can try to do the following
You subscribe to the service and capture the result in a variable
In your case it would be like this
The issue is that the subscribe does not return what is as its parameter, but the subscribe returns a Subscription object.
You could only return
this._login.isLogged()
and subscribe in the part of the code that callscanActivate()
.