Search code examples
angularrxjsobservablehttpclientrxjs5

How to use the Observables from HttpClient and paramMap together for a dynamically loading component?


I have an HTTPClient 'get' method that returns a JSON array of objects. In addition, I'm currently using a key from the route params to extract one object from that array.

The component is dynamic, meaning when the route param changes, the component won't get destroyed.

The Problem

When a new route param is switched, the component doesn't change the selectedUser objecct.

Why?

Because the httpClient completes the observable stream after one emitted item therefore the paramMap observable is also closed so it won't emit when a different value for the route param changes.

ex: '/user/:name'

  1. '/user/bob' ---> component finds the selected user
  2. from the component a new user is entered '/user/john'
  3. '/user/john' ----> component doesn't detect the new param

Here is the code snippet below (users$ is the http.get() observable).

  ngOnInit() {
    this.users$.pipe(
      withLatestFrom(this.params$),
      map( ([users, params]) => {
        return users.find((user) => user.slug === params.landmark);
      })
    ).subscribe(user => this.selecteduser = user);
  }
}

EDIT: Switching to combineLatest does work, but I had to rearrange the observable as such:

  ngOnInit() {
    this.params$.pipe(
      combineLatest(this.users$, this.params$),
      map( ([params, users]) => {
        this.users = users;
        return users.find((user) => user.slug === params.landmark);
      })
    ).subscribe(user => this.selecteduser = user);
  }

Solution

  • Use combineLatest instead of withLatestFrom. This will make the resulted stream active even after one stream completes.

    ngOnInit() {
         combineLatest(this.users$, this.params$).pipe(
          map( ([users, params]) => {
            return users.find((user) => user.slug === params.landmark);
          })
        ).subscribe(user => this.selecteduser = user);
      }