Home > Back-end >  How to conditionally update Angular route resolver data?
How to conditionally update Angular route resolver data?

Time:11-02

I've got an Angular route resolver that has a list of items that gets loaded when my parent route gets loaded, like /users. I have implemented an Angular resolver that looks more or less like this:

export class UsersResolver implements Resolve<UsersResponse> {
  constructor(private usersService: UsersService) {}

  resolve(): Observable<UsersResponse> {
    return this.usersService.getUsers();
  }
}

The child components consume that resolver data in the standard way:

this.route.data.subscribe((data) => {const users = data['users']} )

That works fine...until I perform any action that might change that list (add/delete/alter a user). In that case, I want that resolver to re-run. Well, more specifically, I want the data returned by the resolver to reflect the updated data. I don't think the static options on runGuardsAndResolvers will do the trick, nor do I think in my case that using the function you can hand to runGuardsAndResolvers will work in my case, either, because these data changes might not happen in concert with a route change.

I think what I want is something along the lines of this:

export class UsersResolver implements Resolve<UsersResponse> {
  constructor(private usersService: UsersService) {}

  resolve(): Observable<UsersResponse> {
    return this.usersService.users$;
  }
}

...where this.usersService.users$ is an rxjs Subject. That would mean I could update that subject via other means and (I think) the data in the resolver would update, and therefore any child component subscribed to that resolver would get updated. But if that's right, then where do I trigger the initial data fetch, and how do I ensure that my resolver doesn't actually resolve until the initial data fetch completes?

Is this a common issue with a reasonable solution, or am I going about this in the wrong way?

CodePudding user response:

Angular resolver is there just to provide data while navigation and should not do more.

There are many ways to keep data consistent in your application.

One known way is the state management (store), there are many libraries out there like NgRx that offer the necessary tools to keep your data consistent.

Read this article about state management for more details.

Another way is to build your own simple store concept, by creating a singleton service that spread the change of your data. Then you can subscribe and handle the change in your components.

in your user data service:

data$: Observable<any>;

in your component

data: any;
data$.subscribe(data => this.data = data);

somewhere else in other component

data$.next(data);

Other way is to store your data in a singleton store service and access it directly from your components. The service will have the update and get methods to set and update the data in the service.

CodePudding user response:

I think you are trying something that is not possible. I mean the resolver will be triggered in the route change event so if you change something for that observable after the resolver was completed you won't get that information in your component.

If you want to sync that information with your component I recommend you to subscribe or just use async pipe in your component instead of doing it in your resolver.

If you still want to have your resolver you can merge both observables and handle the changes in your component

CodePudding user response:

It's possible, a little hacky. You might just want to inject UsersService in the component.

But down the garden path:

We return an observable of an observable with a little trick to ensure first emission has occurred and we don't lose this first value.

  resolve(): Observable<Observable<number[]>> {
    const users$ = this.usersService.getUsers();
    return users$.pipe(
      take(1),
      map((firstValue) => {
        return users$.pipe(startWith(firstValue))
      })
    );
  }

Stackblitz

  • Related