You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
router canActivate not working with Observer or Promise response #9613
router canActivate feature not work with Observable response but work with simple boolean response.
see this example :
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>{ console.log('canActivate with AclService'); // if i return boolean, canActivate feature work // return true; // but if i return Observable, canActivate feature not work return Observable.create((observer:Subject<boolean>) => { observer.next(true); }); }
@vicb it's not support request, in the official doc api syntax: canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | boolean; then canActivate returns one of this results : Observable Or a boolean but with the first case Observable , it is not working
Reacted by Tom de Goede, Francisco Arantes, Gaétan Collaud, darin-cardin and Alessandro
Reacted by Dzmitry Shylovich, Trotyl Yu and Max Jacobson
@darwin-gautalius
I think the observable needs to complete. I had more success with .take(1) at the end. That would explain why Observable.of(true) worked.
Try this:
Reacted by Zahir Saad Bouzid, João Paulo Barbosa Marques dos Santos, Günter Zöchbauer, Darwin Gautalius, Cristian Urbano, Łukasz Wojciechowski, John Lindquist, André Werlang, Genevieve L'Esperance, henriquefm and 25 more
Thanks for this. I guess angular2 just keeps waiting for it to finish. I also tried with .first(), instead of .take(1) and using observer.complete() after next and it worked as well. Not sure if there are better practices or problems with any of the approaches that one should know.
Are there any plans to have a guard properly handle as an Observable? I have a problem that I need to wait for a login to happen before telling the guard true or false. If the user goes straight to a url defined as a route say "/admin" then when the canActivate() is called I don't have the user or its rights yet. So I have to default to false. When the login check is made (which is triggered automatically) and it comes back saying "yes, they have admin rights" I set the observable to true. But by then the router has determined that no it is not accessible so the router component does not show. The user then has to click on the link manually to get to the admin page. Since the canActivate() is now true it works, but annoying that I can't go straight to the admin page by typing in the url.
@crowmagnumb
I would try the following approach:
In the service that determines whether the user is admin, and which you'd be able to access from your canActivate function or guard class method, declare this:
private _isAdmin$ = new ReplaySubject(1); // this ensures that the router can always get the most recent value set, but only once it becomes available at all
get isAdmin$() { return this._isAdmin$.asObservable(); }
In your canActivate() function (or guard class method):
return mySecurityService.isAdmin$.first(); // NOTE: this still returns an observable!
And then, once the security service determines if the user has admin privileges, it would set the value:
this._isAdmin$.next(true); // or false if the user is not an admin
I'm doing something very similar, but in my case user information comes as part of page load from the server. So I have an initial value to provide, therefore I'm using BehaviorSubject instead of ReplaySubject with a capacity of 1. In a sense, these two are not very different, with the exception being that the former requires an initial value in the constructor, while the latter allows no value.
I have also performed a test just now by introducing a delay in my canActivate() method, which has proved that the router can wait for a value from the observable, and once it becomes available - will decide whether to navigate to the respective route based on that value.
Hope this helps!
Reacted by RonnyLV, hamidhst, JacobBrandt, Al-Mothafar Al-Hasan, David Domingo, Benjamin Fortenberry, Giovanni Riga, danobri, AmirDolat, Hanna and 2 more
It would be great if there was a way to have it work without requiring the observable to complete. Using a AsyncSubject or BehaviorSubject allows throttling of any Ajax requests made by calling canActivate.
@Snesi Was also not able to get Behavior subject to work. Replay subject works though. Using angular 5 and the same overall implementation as @alobakov suggested but for BehaviorSubject
// Guard method
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
return this._authService.checkTokenAvailability().pipe(
map((response: Response) => {
// return Observable with true value and let the router and the guard to redirect you to dashboard in my case
return true
}),
catchError((err: Response) => {
// navigate to login page
this._router.navigateByUrl('/admin');
// handle the error by throwing statusText into the console
return throwError(err.statusText);
})
);
}
On Fri, Apr 12, 2019, 09:49 Parautiu Razvan ***@***.***> wrote:
Inside AuthGuard I have the following
// Guard method
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
let token = localStorage.getItem("token");
let username = localStorage.getItem("username");
return this._authService.checkTokenAvailability().pipe(
map((response: Response) => {
// return Observable with true value and let the router and the guard to redirect you to dashboard in my case
return true
}),
catchError((err: Response) => {
// navigate to login page
this._router.navigateByUrl('/admin');
// handle the error by throwing statusText into the console
return throwError(err.statusText);
})
);
}
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#9613 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAyu3dutWkMGJ6w9oKsEEJE4PfDHEMN8ks5vgDp_gaJpZM4I-ikg>
.
angular-automatic-lock-bot commented on Sep 14, 2019
Activity
DzmitryShylovich commentedon Jun 26, 2016
Observable.of(true)
vicb commentedon Jun 26, 2016
Your question sounds like a support request.
Please use the issue tracker only for bugs and feature requests.
Use gitter for support request.
aghou commentedon Jun 26, 2016
@vicb it's not support request, in the official doc api syntax: canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | boolean; then canActivate returns one of this results : Observable Or a boolean but with the first case Observable , it is not working
darwin-gautalius commentedon Jun 27, 2016
I'm having the same problem. Here is my guard:
Browser console show
activate? truebut the page doesn't show. The component attached to the path is not initialized too.I tried with
return Observable.of(true);andreturn true;and the page shows correctly.I don't think
canActivatesupportObservable<boolean>only forObservable.of(true).btw, I use this firebase. (just for additional info)
"angularfire2": "2.0.0-beta.0",
"firebase": "2.4.2",
jpsantosbh commentedon Jun 27, 2016
Same here with "@angular/core": "2.0.0-rc.2", "@angular/router": "^3.0.0-alpha.3",
Denhai commentedon Jun 27, 2016
@darwin-gautalius
I think the observable needs to complete. I had more success with
.take(1)at the end. That would explain whyObservable.of(true)worked.Try this:
aghou commentedon Jun 27, 2016
i juste done to test it with .take(1) it's work fine,
thank's @Denhai
darwin-gautalius commentedon Jul 2, 2016
thanks @Denhai. It really works as intended.
PEsteves8 commentedon Jul 5, 2016
Thanks for this. I guess angular2 just keeps waiting for it to finish. I also tried with .first(), instead of .take(1) and using observer.complete() after next and it worked as well. Not sure if there are better practices or problems with any of the approaches that one should know.
philipbulley commentedon Jul 9, 2016
The fact that the Observable needs to complete should be documented, this wasn't obvious to me either.
awerlang commentedon Jul 30, 2016
I sent a PR fixing this issue. Take a look at #10412.
crowmagnumb commentedon Oct 6, 2016
Are there any plans to have a guard properly handle as an Observable? I have a problem that I need to wait for a login to happen before telling the guard true or false. If the user goes straight to a url defined as a route say "/admin" then when the canActivate() is called I don't have the user or its rights yet. So I have to default to false. When the login check is made (which is triggered automatically) and it comes back saying "yes, they have admin rights" I set the observable to true. But by then the router has determined that no it is not accessible so the router component does not show. The user then has to click on the link manually to get to the admin page. Since the canActivate() is now true it works, but annoying that I can't go straight to the admin page by typing in the url.
alobakov commentedon Oct 19, 2016
@crowmagnumb
I would try the following approach:
In the service that determines whether the user is admin, and which you'd be able to access from your canActivate function or guard class method, declare this:
private _isAdmin$ = new ReplaySubject(1); // this ensures that the router can always get the most recent value set, but only once it becomes available at allget isAdmin$() { return this._isAdmin$.asObservable(); }In your canActivate() function (or guard class method):
return mySecurityService.isAdmin$.first(); // NOTE: this still returns an observable!And then, once the security service determines if the user has admin privileges, it would set the value:
this._isAdmin$.next(true); // or false if the user is not an adminI'm doing something very similar, but in my case user information comes as part of page load from the server. So I have an initial value to provide, therefore I'm using BehaviorSubject instead of ReplaySubject with a capacity of 1. In a sense, these two are not very different, with the exception being that the former requires an initial value in the constructor, while the latter allows no value.
I have also performed a test just now by introducing a delay in my canActivate() method, which has proved that the router can wait for a value from the observable, and once it becomes available - will decide whether to navigate to the respective route based on that value.
Hope this helps!
hamidhst commentedon Jun 12, 2017
@alobakov Just Perfect!
After wasting a whole day, you saved it, thanks a lot. (I'm using Angular v4.)
yo-epicdavid commentedon Jun 27, 2017
@alobakov Thank you!
I was using a
BehaviourSubjectand for some reason it wasn't working.raysuelzer commentedon Oct 20, 2017
It would be great if there was a way to have it work without requiring the observable to complete. Using a AsyncSubject or BehaviorSubject allows throttling of any Ajax requests made by calling canActivate.
gang-qiu commentedon Jul 18, 2018
@Snesi Was also not able to get Behavior subject to work. Replay subject works though. Using angular 5 and the same overall implementation as @alobakov suggested but for BehaviorSubject
prashuMishra commentedon Oct 18, 2018
i have the same issue.
app.route.ts.
export const ROUTES: Routes = [
{
path: '',
loadChildren: 'app/login/login.module#LoginModule',
},
{
path: 'home',
loadChildren: 'app/home/home.module#HomeModule',
canActivate: [AuthGuard]
},
{ path: '**', redirectTo: '' },
];
authguard.ts
import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(public auth: AuthService, public router: Router) {}
canActivate(): Observable {
console.log('Canactivate Called');
return Observable.of(true).take(1);
}
}
above code should show "Canactivate Called" in console. but is not working.
RazvanSebastian commentedon Apr 12, 2019
Inside AuthGuard I have the following
And somewhere into the router module you have
yo-epicdavid commentedon Apr 13, 2019
angular-automatic-lock-bot commentedon Sep 14, 2019
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.