38

In ui-router it's easy to make multiple resolves defined in the route configuration, so let's say something like:

export const APP_STATES: Ng2StateDeclaration[] = [
  {
    name: 'dashboard',
    url: '/dashboard', 
    component: DashboardComponent,
    resolve: [
      {
        token: 'playbookDurations',
        deps: [DashboardService],
        resolveFn: (svc: DashboardService) => svc.getPlaybookDurations()
      },
      {
        token: 'playbookSuccesses',
        deps: [DashboardService],
        resolveFn: (svc: DashboardService) => svc.getPlaybookSuccesses()
      },
      {
        token: 'playbookRuns',
        deps: [DashboardService],
        resolveFn: (svc: DashboardService) => svc.getPlaybookRuns()
      },
      {
        token: 'activityLog',
        deps: [DashboardService],
        resolveFn: (svc: DashboardService) => svc.getActivityLog()
      }
    ]
  }
}];

when using the Angular2 router is requires you to implement a resolver pattern for the resolve parameter. So something like this:

import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Injectable } from '@angular/core';
import { DashboardService } from '.';

@Injectable()
export class DashboardResolver implements Resolve<any> {

  constructor(private dashboardService: DashboardService) { }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    return this.dashboardService.get();
  }

}

then in my route I do something like:

import { DashboardComponent } from './dashboard.component';
import { DashboardResolver } from './dashboard.resolver';

export const routes = [
  { 
    path: '', 
    children: [
      {
        path: '', 
        component: DashboardComponent,
        resolve: {
          data: DashboardResolver
        }
      }
    ]
  }
];

problem is there is only ONE resolve. How does one implement multiple resolve arguments as the ui-router implementation does?

I suppose you have 2 options: implement resolvers for each one of those inputs OR have the resolve return an object with all your resolves nested. The first seems pretty ceremonial and the second sounds pretty hacky so there has to be a better way.

4
  • you can proceed with UIRouter in angular2 BTW :), I'm doing so. Commented Jan 9, 2017 at 14:32
  • 2
    Yes, I know. I'm just experimenting ;P Commented Jan 9, 2017 at 14:32
  • @amcdnl. Do you still need help with this? Commented Feb 23, 2017 at 14:40
  • 1
    I think any feedback would help everyone @AngularFrance Commented Mar 2, 2017 at 12:59

2 Answers 2

62

Alright, I hope I haven't misunderstood the question.

Angular's router supports as many resolvers per route as you want.

In the route declaration, the resolve property is an object and it can have as many keys as you'd like:

{
  path: '', 
  component: DashboardComponent,
  resolve: {
    foo: Resolver1
    bar: Resolver2,
    // more resolves here...
  }
}

Then retrieve the resolved data from your component:

@Component({ ... })
export class MyComponent {

  constructor(private route: ActivatedRoute) { }

  ngOnInit() {
    const foo = this.route.snapshot.data['foo'];
    const bar = this.route.snapshot.data['bar'];
  }

}

The route won't be activated until ALL resolves are complete/fulfilled.

Sign up to request clarification or add additional context in comments.

5 Comments

So this is good to know for sure but I don't think it quite answers his entire question. Do we have to create x number of injectable resolver classes for each resolve we want in a route or how do we go about making a single resolver that would make multiple service calls before the route is activated?
It's a design choice and it's up to you. One bulky resolver will make it less reusable. Unless your resolver is tied to one specific route, I think composing multiple nimble resolvers is a better approach.
Hello, is possible to get one root object with some nested object? I'd like to get one object with nested objects instead many resolvers.
The data returned by the resolver can be anything you want, it's just an object literal. But there's no built-in mechanism to aggregate the data from multiple resolvers into a single nested object. You could probably do it manually, though, by having a "master" resolver that accesses and aggregates the data from other resolvers. But I really don't think it's a good idea, it makes your code less explicit and harder to debug.
I am getting the second one undefined. any solutions?
2

You can achieve the same results while using ONLY ONE RESOLVER:

resolve(route: ActivatedRouteSnapshot,state: RouterStateSnapshot,): Observable<any> {
    let companyIdentifierTypes = this.companiesService.getCompanyIdentifierTypes();
    let mobilePrefixes = this.registrationService.getMobilePrefixes();
    let data = {companyIdentifierTypes: companyIdentifierTypes, mobilePrefixes: mobilePrefixes};
    return Observable.of(data);
}

and fetch the resolved data this way:

fetchDataBeforeViewRender() {
    let data =  this.route.snapshot.data['data'];
    if(data != null) {
        data.companyIdentifierTypes.subscribe(data => {this.identityTypeIDList = data;});
        data.mobilePrefixes.subscribe(data => {this.mobilePrefixOptions = data;});
    }
}

make sure to name the resolver correctly!

2 Comments

if the three functions are calling any Database objects or HTTP calls then will these work asynchronously ?
You should combine them via merge/concat/forkJoin so you have 1 subscription. And then just return the observable and let the work be done async. If one of those subs fails, how would that be handled properly?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.