Justin
Justin

Reputation: 4263

Pass result of one resolve to another with Angular Router

I know how to create multiple resolve classes for a route but I don't know how to pass the result of one resolve to another resolve.

// Example Route
{
  path: 'book/:id',
  component: BookComponent,
  resolve: {
    document: BookResolve,
    title: BookTitleResolve
  }
}

If the BookResolve returns a book object, how can you pass that book object to the BookTitleResolve?

I have a title service that looks for the key title in data. I need to be able to generate the book title from the book object. This needs to be dynamic.

Upvotes: 13

Views: 4759

Answers (2)

FarzadJamshidi
FarzadJamshidi

Reputation: 137

First of all, omit document resolver from route and keep only title resolver (last resolver) like this:

// Example Route
{
  path: 'book/:id',
  component: BookComponent,
  resolve: {
    title: BookTitleResolve
  }
}

then re-write BookTitleResolve as follow:

export class BookTitleResolve implements Resolve<string> {

    constructor(
      private router: Router,
      private bookResolver : BookResolve,
      private sampleObservableServise : SampleObservableServise
    ) { }

    // add 'async' to resolve method, so we can call resolvers in turn 
    // and wait for response before go to next resolver
    async resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<string> {
  
      // should convert resolver from observable to promise because of using 'await'
      // So, we get bookObject before go to next resolver
      const bookObject = await this.bookResolver.resolve(route, state).toPromise().then( res => {
        return res;
      });
  
  
      // this is final resolver. Again, we should convert resolver from observable to promise
      // because of using 'await'
      return await this.sampleObservableServise.toPromise().then(val => {
        return val
      }, () => {
        this.router.navigate(['/']);
        return null
      })
  
    }
  
  }

In conclusion, we should keep only last resolver in route object, in this case:

title: BookTitleResolve

then by using async/await, call other resolvers one by one in your desire order and use their data.

Upvotes: 2

DNJohnson
DNJohnson

Reputation: 776

Resolves within the same component run concurrently but resolves in parents will complete before children so the easiest way to achieve this is to create a parent route with the purpose of resolving the book.

{
  path: 'book/:id',
  resolve: {
    document: BookResolve
  },
  children: [ {
    path: '',
    component: BookComponent,
    resolve: {
      title: BookTitleResolve
    }
  } ]
}

Note that the parent doesn't render a component and the child contains a blank path so despite some added boilerplate, the route should act the same functionally.

Then inside your BookTitleResolve implementation, you can retrieve from the parent route:

class BookTitleResolve {
    resolve(route: ActivatedRouteSnapshot) {
        // Do something with route.parent.data.document
    }
}

Upvotes: 12

Related Questions