8

resolve method in the example on the angular.io returns a promise or navigates the application to the specific route if no data was found.

resolve(route: ActivatedRouteSnapshot): Promise<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;
  }
});
}

suppose, that getCrisis function returning an observable:

resolve(route: ActivatedRouteSnapshot): Observable<any> {
  let id = +route.params['id'];
  return this.cs.getCrisis(id).take(1)
}

in case of observable. How do i know, that nothing is returned, as i am dealing with stream? what would be the best pattern to handle this case inside the resolve function?

I know, that i could user router.navigate method from the component, but would like to use the router resolve guard properly.

Alex
  • 578
  • 6
  • 19

2 Answers2

9

You might need to add .first() (needs to be imported) because currently the router waits for the observable to complete and that might not happen depending on what getCrisis() is doing:

resolve(route: ActivatedRouteSnapshot): Observable<any> {
  let id = +route.params['id'];
  return this.cs.getCrisis(id)
  .map(data => {
    if(data) {
      return crisis;
    } else {
      this.router.navigate(['/crisis-center']);
      return false;
    }
  })
  .first()
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • i've updated my question with resolve method, that returning an abservable – Alex Sep 09 '16 at 11:00
  • I updated my answer. Just change `then` to `map` ;-) – Günter Zöchbauer Sep 09 '16 at 11:02
  • .first() here is the emiter of the observable, right? so no subscribe is needed? – mahatmanich Feb 17 '17 at 15:11
  • 1
    `first()` is a filter that, only emits the first value (of a possible stream of values) and because there won't be a second event from this the resulting observable, it is closed just after the first value. The router subscribes to the returned observable, therefore there is no point in subscribing in the guard anyway. If you would ass `subscribe(...)` the returned value would be a `Subscription` instead of an `Observable` which wouldn't work. – Günter Zöchbauer Feb 17 '17 at 15:16
  • 1
    `first()` is to ensure the router only waits for one value and then continues, otherwise it would wait for the observable to complete, which only happens when routed away from this route, which wouldn't make sense in this context. I'm not sure if `first()` is still necessary. I remember discussions, that the router itself should do this, but I don't know if this behavior was actually changed or not. – Günter Zöchbauer Feb 17 '17 at 15:16
  • Just removed `first()` data is still working. I also do not use `subscribe`? So would that mean it is all built in? – mahatmanich Feb 17 '17 at 15:55
  • Not sure what you mean with "built in". You pass the observable to the router, and the router subscribes to get notified about the response. – Günter Zöchbauer Feb 17 '17 at 15:57
  • The router calls `resolve(...)` (the one shown in my answer) and gets an `Observable` passed as return value, where the router calls `subscribe()` on, to get notified when a value arrives. – Günter Zöchbauer Feb 17 '17 at 16:06
  • Yes I see that. I have a similar setup, however the resolve calls an observable from another data service and passes it on to the router. The data gets to the front without any problems without ever having to call subscribe ... – mahatmanich Feb 17 '17 at 16:12
  • Not sure what's unclear. The router calls `subscribe()` on it. – Günter Zöchbauer Feb 17 '17 at 16:15
  • So the router automatically calls subscribe() on it? – mahatmanich Feb 17 '17 at 16:19
  • 1
    Sure, that's what it does. – Günter Zöchbauer Feb 17 '17 at 16:20
  • Hi @GünterZöchbauer can you have a look at that if you have time? http://stackoverflow.com/questions/42367754/angular2-router-with-http-data-service-through-a-resolve-with-observable-catchin – mahatmanich Feb 21 '17 at 12:58
  • for some reason, in my component, this.route.data.subscribe() gives me an array [myValue], rather than just giving me myValue, anyone know why the value I returned in my resolver was put into an array before being passed to my component? – Rusty Rob Jun 21 '17 at 08:14
  • See https://angular.io/guide/router#fetch-data-before-navigating. You get a `Data` instance which can contain more than one value, therefore you get it using the name. Like `data.crisis` – Günter Zöchbauer Jun 21 '17 at 08:23
0

From angular 6, first() is not there in Observable. Below code works now.

resolve(route: ActivatedRouteSnapshot): Observable<any> {
  let id = +route.params['id'];
  return this.cs.getCrisis(id)
  .map(data => {
    if(data) {
      return crisis;
    } else {
      this.router.navigate(['/crisis-center']);
      return false;
    }
  })
  .pipe(first())
}
Lahiru Chandima
  • 22,324
  • 22
  • 103
  • 179