Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Executing resolvers one after the other in Angular 2+

Given the following route:

path: '',
component: MyComponent,
resolve: {
    foo: FooResolver,
    bar: BarResolver
}

Is there any way of telling angular to execute the first resolver FooResolver, and only execute the second resolver BarResolver once the first one has finished?

like image 212
Ivan Aguilar Avatar asked Oct 17 '17 14:10

Ivan Aguilar


People also ask

How do resolvers work angular?

So what is Angular Resolver? Angular Route Resolver is used for pre-fetching some of the data when the user is navigating from one route to another. It can be defined as a smooth approach for enhancing user experience by loading data before the user navigates to a particular component.

What is the use of resolve object in routing?

Resolvelink A data provider class can be used with the router to resolve data during navigation. The interface defines a resolve() method that is invoked right after the ResolveStart router event. The router waits for the data to be resolved before the route is finally activated.

What is the correct way to add a basic route in angular?

First, add links to the two components. Assign the anchor tag that you want to add the route to the routerLink attribute. Set the value of the attribute to the component to show when a user clicks on each link. Next, update your component template to include <router-outlet> .


2 Answers

Resolvers are resolved in parallel. If Foo and Bar are supposed to be resolved in series they should be a single FooBar resolver. If they are supposed to be used by themselves in other routes, FooBar can wrap Foo and Bar resolvers:

class FooBarResolver implements Resolve<{ foo: any, bar: any }> {
  constructor(
    protected fooResolver: FooResolver,
    protected barResolver: BarResolver
  ) {}

  async resolve(route): Promise<{ foo: any, bar: any }> {
    const foo = await this.fooResolver.resolve(route);
    const bar = await this.barResolver.resolve(route);

    return { foo, bar };
  }
}

FooBar should be aware of the fact if it is a promise or an observable that is returned from Foo and Bar in order to resolve them properly. Otherwise additional safety device should be added, like await Observable.from(this.fooResolver.resolve(route)).toPromise().

FooBar and Foo or Bar shouldn't appear within same route because this will result in duplicate resolutions.

like image 99
Estus Flask Avatar answered Sep 20 '22 15:09

Estus Flask


I found a slightly more elegant solution that can be used if you don't care about the results from all of the resolvers:

class FooBarResolver implements Resolve<Observable<any>> {
    constructor(
        protected fooResolver: FooResolver,
        protected barResolver: BarResolver
    ) { }

    resolve(): Observable<any>
    {
        return this.fooResolver.resolve().pipe(
            concat(this.barResolver.resolve()),
            concat(this.barResolver.resolve())
        );
    }
}

I use this to trigger the data loading in my services. And because they write the data / isLoading / error into an Akita storage, I don't care about the results of the resolvers.

like image 36
C. Fritz Avatar answered Sep 20 '22 15:09

C. Fritz