Star
0
Published Jul 25, 2016Last updated Nov 16, 2016

How to Use Resolve in Angular 2 Routes

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.

Sharing Data in AngularJS: Be Aware of $watch
Build Custom Directives in Angular 2
React vs Angular 2: Comparison Guide for Beginners
Star
0