0

I´ve got a Component which loads user data and should be able to handle direct accessing via url. My idea was to implement a resolver service in the router, which is allready working fine when accessing the component via routing through the application. But if I refresh the application on the url, the resolver service throws following error:

ERROR Error: "Uncaught (in promise): TypeError: this.userService.getCurrentUser() is undefined

It seems like the userService is not initialized fast enough when refreshing.

This is the resolver service:

@Injectable({
  providedIn: 'root'
   })
export class UserResolverService {

 constructor(private userService: UserService, private authService: AuthService, private router:Router) { }

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<User> | Observable<never> {
let id = route.paramMap.get('id');


 //return this.authService.checkToken().subscribe(res => {
if(this.authService.checkToken()){
  return this.userService.getCurrentUser().pipe(take(1), mergeMap(user => {
    if(user){
      return of(user);
    } else {
      this.router.navigate['/login'];
      return EMPTY;
    }
  }));
} else {
  this.router.navigate['/login'];
      return EMPTY;
}

 }

 }

This is the UserService method called:

getCurrentUser(): Observable<User>{
if(this.currentUser.value != null){
  return this.currentUser.asObservable().pipe(filter(user => user != null));
} else {
  this.setCurrentUser().subscribe(res => {
    return this.currentUser.asObservable().pipe(filter(user => user != null));
  })
}

The setCurrentUser() method get calls the backend with credentials to retrieve the user Data.

The contructor of the Component, which should be able to load its data when refreshing contains the following:

this.route.data.subscribe((data: {user: User}) => {
  this.user = data.user;
  this.initialDialogWindows();
  this.initialViewGuidingVariables();
});

EDIT:

I changed it to the suggested solution of Aakash Garg. Now the ngOnit() methods only receive undefined and the resolver does not seem to wait for promises. Neither of the console logs beside "am I even here?" are executed.

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<User> {
let id = route.paramMap.get('id');


 //return this.authService.checkToken().subscribe(res => {
if(this.authService.checkToken()){
  console.log("am I even here?");
   this.userService.getCurrentUserPromise().then(user => {
     console.log("resolved user:" + user);
    if(user){
      return of(user);
    } else {
      console.log("navigating to login");
      this.router.navigate['/login'];
      return EMPTY;
    }
  });
} else {
  console.log("navigating to login, because there is no token");
  this.router.navigate['/login'];
      return EMPTY;
}

 }
Zytro
  • 15
  • 4

1 Answers1

0

The problem is not of service initialization, but the way your getCurrentUser method is written. because in case where currentUser.value is null it will not wait for subscription to complete and return undefined. that's how async tasks work. change your getCurrentUser Method to :-

    async getCurrentUser(): Promise<User>{
      if(this.currentUser.value != null){
        return this.currentUser.asObservable().pipe(filter(user => user != null)).toPromise();
      } else {
        await this.setCurrentUser().toPromise();
        return await this.currentUser.asObservable().pipe(filter(user => user != null)).toPromise();
      }
    }

And Change your resolver to :-

@Injectable({
  providedIn: 'root'
   })
export class UserResolverService {

 constructor(private userService: UserService, private authService: AuthService, private router:Router) { }

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<User> | Observable<never> {
let id = route.paramMap.get('id');


 //return this.authService.checkToken().subscribe(res => {
if(this.authService.checkToken()){
  this.userService.getCurrentUser().then(user => {
    if(user){
      return of(user);
    } else {
      this.router.navigate['/login'];
      return EMPTY;
    }
  });
} else {
  this.router.navigate['/login'];
      return EMPTY;
}

 }

 }
Aakash Garg
  • 10,649
  • 2
  • 7
  • 25
  • tryed this, but now the resolver allways returns undefined. Seems like the view is still rendered before the the promise of the service is resolved in the resolver. – Zytro Jun 17 '20 at 06:48