Resolve a value *before* activating a route in Angular 2

10,116

Update

This is implemented in the new router >= RC.4

import { Injectable }             from '@angular/core';
import { Router, Resolve,
         ActivatedRouteSnapshot } from '@angular/router';
import { Observable }             from 'rxjs/Observable';
import { Crisis, CrisisService } from './crisis.service';
@Injectable()
export class CrisisDetailResolve implements Resolve<Crisis> {
  constructor(private cs: CrisisService, private router: Router) {}
  resolve(route: ActivatedRouteSnapshot): Observable<any> | Promise<any> | any {
    let id = +route.params['id'];
    return this.cs.getCrisis(id).then(crisis => {
      if (crisis) {
        return crisis;
      } else { // id not found
        this.router.navigate(['/crisis-center']);
        return false;
      }
    });
  }
}

Original

Maybe the router in its current state isn't finalized and there will be a better way when a stable Angular 2 is released?

That's actually the case. There were lots of discussions recently about further progress and several changes are planned.

See also
- Angular Weekly Meeting (April 4)
- Router: Design for routerCanActivate, an injectable alternative to @CanActivate

I have seen people write their data into a property of the next parameter of the decorator, and retrieve it in the next parameter of the routerOnActivate method.

AFAIK the params is supposed to be immutable and should not be modified.

The discussions in [router] CanActivate and DI show how to use DI with CanActivate. This is the approach I would use. Share a service globally and inject it in CanActivate to update the values and inject it also in the components where you want to get access to the value.

Share:
10,116

Related videos on Youtube

AngularChef
Author by

AngularChef

Formations et tutos Angular en français - https://www.angularchef.com/

Updated on July 16, 2022

Comments

  • AngularChef
    AngularChef almost 2 years

    I'd like to prevent a route from being accessed as long as a promise hasn't been resolved. Also, I'd like to pass the return value of that promise to the route component.

    Several posts on SO recommend using the OnActivate interface for this. The documentation says: "If routerOnActivate returns a promise, the route change will wait until the promise settles to instantiate and activate child components." Sounds perfect, only the route still gets activated immediately... (Is it because it's the child components of Route2 that will wait for the promise, not the Route2 component itself??)

    See https://plnkr.co/edit/ipKrOgfRj0vKk8ZejH5v?p=preview. The Route2 component implements the OnActivate interface, but when you click the Route2 link, the Route2 component is activated immediately. However, the URL does update to /route2 only after the promise has resolved. (Launch the Plunker in a separate window to see what I mean.) Now I don't care so much about the URL, the Route2 component should not instantiate at all until the promise is resolved.

    My other strategy was to use the @CanActivate decorator. It better suits my purpose as "it is called by the router to determine if a component can be instantiated as part of a navigation".

    The problem here is how to pass data from the promise in the @CanActivate decorator to the component?

    I have seen people write their data into a property of the next parameter of the decorator, and retrieve it in the next parameter of the routerOnActivate method.

    For instance in next.params (here):

    @CanActivate((next) => {
      return messageService.getMessage()
          .then((message) => {
             next.params.message = message;
             return true;
          });
    })
    export class MyComponent implements OnActivate {
      routerOnActivate(next) {
        this.message = next.params.message;
      }
    }
    

    Or in next.routeData.data (here).

    But the documentation says ComponentInstruction objects "should be treated as immutable". This is confusing.

    Is this the best way to do this?

    Maybe the router in its current state isn't finalized and there will be a better way when a stable Angular 2 is released?

  • Günter Zöchbauer
    Günter Zöchbauer about 8 years
    AFAIR there are open issues about the other methods not waiting for the promise to resolve.