When I reload my page, it always goes to blank page instead of the same page. The reason behind this is canActivate method which is cheking for user's permission gets invoked as soon as user refreshes the page and it is not able to get user data immediately. User data comes after some seconds. Is there any way to make canActivate method wait till data comses? I have been going through RxJS's page but not understanding how to do it. Can someone suggest me any ideas?
constructor(private router: Router, private userDataService: UserDataService) {
userDataService.userData$.subscribe(
(data: User) => {
this.userData = userData --> comes after some seconds
}
);
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree
{
const result = this.getUserData(route);
if (!result) {
this.blankPage();
}
return result;
}
public getUserData(): Observable<boolean> {
if (this.userData) {
check for permissions...
return of(true);
}
return of(false);
}
userdata.service.ts:
userDataSubscription: Subscription;
userData: BehaviorSubject<User> = new BehaviorSubject<User>(null);
public userData$: Observable<User> = this.userData.asObservable();
private getUserData(): void {
const userData$ = new Observable(
subscriber => subscriber.next(new User())
).pipe(
delay(1000),
mergeMap((model: User) => this.getUserInfo(model)),
mergeMap((model: User) => this.getUserPermission(model)),
catchError((err, caught) => {
console.error('failed')
return caught;
})
);
this.userContextDataSubscription = userData$.subscribe(
(data: User) => {
this.userData,next(model);
},
() => console.error('failed')
);
}
CodePudding user response:
You probably want to use an Angular resolver here instead of a guard. A resolver ensures data is available and loaded before a route loads.
There are lots of useful tutorials, just search for "Angular Resolver".
A resolver returns an Observable. You probably want to use the RxJS filter and take(1) operators. Something like this:
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<any>|Promise<any>|any {
return this.service.getMyData(route.paramMap.get('id')).pipe(
filter(x => !!x),
take(1)
)
}
Filter here ensures the data is a truthy value. Then take(1) basically says I got what I need. All the best.
CodePudding user response:
canActive
is an asynchronous method it means you can return Observeble or Promise and the route will not be loaded until Observable/Promise gets resolved
here is an example of correct canActivate
usage:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree
{
return this.userDataService.userData$
.pipe(take(1))
.pipe(map(user => {
let result: boolean
// check your permissions
if (!result) {
this.redirectToBlankPage();
return false;
}
return result;
}));
}