Executing resolvers one after the other in Angular 2+

后端 未结 4 1564
孤城傲影
孤城傲影 2021-02-04 03:50

Given the following route:

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

Is there any way of tell

相关标签:
4条回答
  • 2021-02-04 04:37

    I tackled this scenario using combineLatest in a single resolver. You can do this:

    @Injectable({providedIn: 'root'})
    export class FooBarResolver implements Resolve<any> {
      constructor(
        private readonly fooResolver: FooResolver,
        private readonly barResolver: BarResolver  
      ) {}
    
      resolve() {
        return combineLatest(
          this.fooResolver.resolve(), 
          this.barResolver.resolve()
        ).pipe(map(([users, posts]) => ({users, posts})))
      }
    }
    
    0 讨论(0)
  • 2021-02-04 04:41

    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.

    0 讨论(0)
  • 2021-02-04 04:48

    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.

    0 讨论(0)
  • 2021-02-04 04:50

    One other option is to wrap your dependent routes and use necessary resolver on wrapper.

    I.E.

    { path: '', resolve: { foo$: FooResolver }, children: [
        { path: 'mySubRoute', resolve:  {bar$: BarResolver }, component: BarComponent }
    ]}
    

    *If you meet with relative path resolving problems, try using

    relativeLinkResolution: "corrected"
    

    In forRoot router method. More info here Angular RouterLink relative path does not work in component having empty path

    0 讨论(0)
提交回复
热议问题