Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using NGRX in a Route Resolver

I am using Angular 6. I am also using NGRX Store. I am using a route guard to make sure the user is logged in to the application. I then use a resolver to get the initial user profile, then place it in the NGRX store.

I am new to NGRX and I am not sure if this is the correct way to write the resolver.

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): any {
     return this.loginService.getLoginData()
        .pipe(
            map((result:UserData) => { 
                this.store.dispatch(new userActions.SetLoginData(result)); 
                this.loginService.getDropdownData(
                    result.userId, 
                    result.countryCode,
                ).subscribe( data => { 
                    this.store.dispatch(new userActions.SetDropdownData(data));
                })
            })
        )
}  

I am also not sure if this is the correct way to do the RXJS.

any suggestions, Thanks

like image 717
Troy Avatar asked Oct 20 '25 17:10

Troy


2 Answers

I'm going to point you to Preloading ngrx/store with Route Guards, an article of Todd Motto which explains it really well.

There is also an example of the guard in the NgRx example app

@Injectable()
export class CoursesGuard implements CanActivate {
  constructor(private store: Store<CoursesState>) {}

  getFromStoreOrAPI(): Observable<any> {
    return this.store
      .select(getCoursesState)
      .do((data: any) => {
        if (!data.courses.length) {
          this.store.dispatch(new Courses.CoursesGet());
        }
      })
      .filter((data: any) => data.courses.length)
      .take(1);
  }

  canActivate(): Observable<boolean> {
    return this.getFromStoreOrAPI()
      .switchMap(() => of(true))
      .catch(() => of(false));
  }
}
like image 153
timdeschryver Avatar answered Oct 25 '25 21:10

timdeschryver


First of all I think it would make sense to seperate the authentication check and the data resolution into separate classes. For authentication it makes more sense to use a CanActivate guard. See: https://angular.io/api/router/CanActivate

With this out of the way your resolver can focus on only getting the data that is actually required. Here you need to be aware that if you return an observable in your resolver, the observable needs to complete in order for the resolver to complete. The problem is that if you select something from the store, the resulting observable never completes, hence your resolver will never finish resolving your data. You can work around this fact by using the first() or take(1) operator. timdeschryvers answer has a nice example on how to accomplish that.

like image 34
tom van green Avatar answered Oct 25 '25 21:10

tom van green