Kyle
Kyle

Reputation: 322

Using Resolve In Angular2 Routes

In Angular 1 my config looks like this:

$routeProvider
  .when("/news", {
    templateUrl: "newsView.html",
    controller: "newsController",
    resolve: {
        message: function(messageService){
            return messageService.getMessage();
    }
  }
})

How to use resolve in Angular2?

Upvotes: 32

Views: 26360

Answers (5)

Alireza
Alireza

Reputation: 104650

You can create your Resolver in Angular2+ and apply it to the router quite easily. look at the below, here is the way to create the Resolver in Angular:

@Injectable()
export class AboutResolver implements Resolve<Message> {

  constructor(private aboutService: AboutService, private router: Router) {}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
    const id = route.params['id'];
    return this.aboutService.getById(id);
  }
}

then in the router config:

export const Routes: RouterConfig = [
  { path: 'about',  component: AboutComponent, resolve: { data: AboutResolver } }
]; 

and finally in your component:

ngOnInit() {
  this.route.data.subscribe((data: { about: About }) => {
    this.about = data.about;
  });
}

Upvotes: 5

Paysdoc
Paysdoc

Reputation: 299

As alexpods has already mentioned, there doesn't seem to be a 'resolve' as such. The idea seems to be that you make use of the lifecycle hooks that the router provides. These are:

  • canReuse
  • canDeactivate
  • onActivate
  • onReuse
  • onDeactivate

Then there is @CanActivate. This is a special hook because it is called before your component is instantiated. Its parameters are (next, previous) which are the components you're routing to and the component you've come from (or null if you have no history) respectively.

import {Component} from '@angular/core';
import {ROUTER_DIRECTIVES, CanActivate, OnActivate} from '@angular/router';

@Component({
    selector: 'news',
    templateUrl: 'newsView.html',
    directives: [ROUTER_DIRECTIVES]
})

@CanActivate((next) => {
    return messageService.getMessage()
        .then((message) => {
            next.params.message = message;
            return true; //truthy lets route continue, false stops routing
        });
})

export class Accounts implements OnActivate {

    accounts:Object;

    onActivate(next) {
        this.message = next.params.message;
    }
}

The thing I have not figured out yet is how to get the result of the promise into your onActivate - other than storing it on your 'next' component. This is because onActivate is also only invoked with next and previous and not the result of the promise. I'm not happy with that solution but it's the best I could come up with.

Upvotes: 28

Steve Brush
Steve Brush

Reputation: 3181

@AndréWerlang's answer was good, but if you want the resolved data on the page to change when the route parameter changes, you need to:

Resolver:

@Injectable()
export class MessageResolver implements Resolve<Message> {

  constructor(private messageService: MessageService, private router: Router) {}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Message> {
    const id = +route.params['id'];
    return this.messageService.getById(id);
  }
}

Your component:

ngOnInit() {
  this.route.data.subscribe((data: { message: Message }) => {
    this.message = data.message;
  });
}

Upvotes: 4

Andr&#233; Werlang
Andr&#233; Werlang

Reputation: 5944

Based on @angular/router v3-beta, these are the required steps.

Implement a resolver that returns an Observable or a plain value:

@Injectable()
export class HeroResolver implements Resolve {

    constructor(
        private service: HeroService
    ) {}

    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Hero> {
        const id = +route.params['id'];
        return Observable.fromPromise(this.service.getHero(id));
    }

}

Note that in case you return an observable, the unwrapped value (first one) will be available through route.snapshot.data. If you want the observable itself to be available, then you need to wrap it in another Observable:

return Observable.of(source$);

Add the resolver to your route:

export const HeroesRoutes: RouterConfig = [
    { path: 'heroes',  component: HeroListComponent, resolve: { heroes: HeroesResolver } },
    { path: 'hero/:id', component: HeroDetailComponent, resolve: { hero: HeroResolver } }
];

Finally, provide your resolve class and any dependency to bootstrap or your main component providers:

bootstrap(AppComponent, [
    HeroesResolver, HeroService
])

Consume the resolved data from an ActivatedRoute instance:

ngOnInit() {
    this.hero = this.route.snapshot.data['hero'];
}

Remember that snapshot means the value at the state of execution, both in the component class and the resolver class. Data can't be refreshed from params updates with this approach.

Plunker: http://plnkr.co/edit/jpntLjrNOgs6eSFp1j1P?p=preview Source material: https://github.com/angular/angular/commit/f2f1ec0#diff-a19f4d51bb98289ab777640d9e8e5006R436

Upvotes: 28

Vitali Kniazeu
Vitali Kniazeu

Reputation: 1087

https://angular.io/docs/ts/latest/api/router/index/Resolve-interface.html "resolve" has been brought back to angular2 router, but the documentation is sparse.

Example:

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
    }
  }])
);

Upvotes: 9

Related Questions