Write a post

Enjoy this post? Give Max Diachenko a like if it's helpful.

How to Use Resolve in Angular 2 Routes

Published Jul 25, 2016Last updated Jan 18, 2017
How to Use Resolve in Angular 2 Routes

Resolve is a powerful technique to achieve the best user-experience when browsing between pages in your app. It also makes the controller's code much cleaner in contrast to fetching data inside the controller.

Just one tip: do not overuse the resolves

Load only important data in resolves to render main parts of the page immediately and fetch all other data, asynchronously.

Angular1 vs Angular2

In Angular1, we could see the following code to define resolves in router (ui-router):

$stateProvider
  .state('transactions.details', {
    url: '/transactions/:id',
    views: {
      content: {
        controller: 'TransactionCtrl',
        templateUrl: 'transaction.html',
        resolve: {
          transactions: function (Transaction, $stateParams) {
            return Transaction.getById($stateParams.id);
          }
        }
      }
    }
  })

In Angular 2.0.0-rc.4 router, you can do similar stuff but with some key differences:

// main.ts

import { TransactionResolver } from './resolvers/transaction.resolver.ts';

export const routes: RouterConfig = [
  {
    path: 'transactions/:id',
    component: TransactionComponent,
    resolve: {
      transaction: TransactionResolver
    }
  }
];

bootstrap(AppComponent, [
  provideRouter(routes)
])

As you can see, it is pretty much the same except that we pass TransactionResolver class instead of function.

How to implement a Resolver class

Create new folder called resolves and put resolvers with name template <resolveName>.resolver.ts:

// transaction.resolver.ts

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Rx';
import { TransactionService } from '../services/transaction.service';

@Injectable()
export class TransactionResolver implements Resolve<any> {
  constructor(
    private transactionService: TransactionService
  ) {}

  resolve(route: ActivatedRouteSnapshot): Observable<any> {
    return this.transactionService.getById(route.params.id);
  }
}

  • The exported class should be Injectable
  • The class should implements Resolve<any> interface with one method resolve(): Observable<any>

Why is this example different from Angular 1's docs?

In Angular 2 Docs in Resolve we can see:

class TeamResolver implements Resolve {
  constructor(private backend: Backend) {}
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<any> {
    return this.backend.fetchTeam(this.route.params.id);
  }
}
bootstrap(AppComponent, [
  TeamResolver,
  provideRouter([{
    path: 'team/:id',
    component: TeamCmp,
    resolve: {
      team: TeamResolver
    }
  }])
);

But if you execute this code you will face 2 errors:

  1. Generic type 'Resolve<T>' requires 1 type argument(s).
  2. TypeError: Cannot read property 'params' of undefined.

I can't explain why the interface Resolve requires any argument types, but to make it work just add <any> argument type to Resolve.

resolve() gets 2 arguments while it's executing, but this.route tries to get the property of this class with name route, which is not correct. Just use route.

Still, I don't know why the Documentation is unseemly and uninformative. I spent hours to make resolves work in Angular 2, so hope this article will help somebody.

Discover and read more posts from Max Diachenko
get started
Enjoy this post?

Leave a like and comment for Max

11Replies
chris marx
3 months ago

This is well documented now - https://angular.io/docs/ts/…

Brian
5 months ago

Very helpful article. Thanks!

If this.transactionService.getById(route.params.id) returns an error, you can catch it with your call to navigate. What happens if the source is external though? How do you prevent your application from crashing?

I.e. I navigate to my route from my home page. An error occurs. I catch it and recover.
vs
I navigate to my route from my bookmarks. There’s no caller and no context since this wasn’t called by my application but manually via a browser URL. An error occurs. Because there’s no caller, this error isn’t caught and crashes the application.

Thanks,
Brian

Brian
5 months ago

In case it helps anyone, Angular allows you to override the built in error handling with a class implementing ErrorHandler (https://angular.io/docs/ts/…). This allows you to implement your own custom error handling and recover gracefully from framework level exceptions such as the routing question I posted above.

Timothy Lang
6 months ago

This worked great, thanks!

Show more replies

Subscribe to our weekly newsletter