0

i'am implementing angular solution to get all items in database first , after termination i then get the current selected box from database , then mapping the items to the box. i need that all the items are charged then getting the box at the end do the mapping , i have the following code that works but it s a litle bit dirty by doing a nested observables , any one of you have a cleaner solution?? i found on the documentation the solution os swithMap but i think that it is not appropriate to my case because a switch map does not work the upper observable to finish to execute the inner one

this.getItems().subscribe(items => {
        this.itemsInDataBase = items;
    this.loadActiveBox().subscribe(box => {
        this.selectedBox= box;

        this.selectedBox?.versions.forEach((version, index) => {
            this.itemsInDataBase.forEach((itemInDatabase, index) => {
                version.items.forEach((item, index) => {
                        this.insertItemInbox(item, itemInDatabase, version);
                    }
                );
            });
        });

grazie mille

Ares
  • 71
  • 1
  • 10
  • If you want to add an order to your calls, `concatMap` would be a viable option, see https://www.learnrxjs.io/learn-rxjs/operators/transformation/concatmap – Aldin Bradaric Nov 11 '21 at 12:28
  • with concat map i have to add delays , i thing that it is not that clean. – Ares Nov 11 '21 at 12:32
  • The only delay I could see here is concatMap waiting for your outer observables to finish. Which you're doing right now anyway, so I wouldn't see a problem there. Anyway, in the meantime Michael's posted a good alternative. – Aldin Bradaric Nov 11 '21 at 12:40

1 Answers1

1

RxJS switchMap operator could be used where the inner observable depends on the outer observable. In your case, since both observables appear to be independent, you could use the forkJoin function.

forkJoin({
  items: this.getItems(),
  box: this.loadActiveBox()
}).pipe(
  tap({
    next: ({items, box}) => {
      this.itemsInDataBase = items;     // <-- are these needed?
      this.selectedBox = box;
    }
  })
).subscribe({
  next: ({items, box}) => {
    box?.versions.forEach(version =>
      items.forEach(itemInDatabase =>
        version.items.forEach(item =>
          this.insertItemInbox(item, itemInDatabase, version)
        )
      )
    )
  },
  error: (error: any) => {
    // handle errors
  }
});
ruth
  • 29,535
  • 4
  • 30
  • 57
  • the two observables are dependent , i have to get all my items first then execute the second observable. – Ares Nov 11 '21 at 12:41
  • @Ares: Does the HTTP request `this.loadActiveBox()` depend on the response from the `this.getItems()` request? Note that I am asking about the request. Not what is done with their responses. – ruth Nov 11 '21 at 12:43
  • the requests are independant but the responses yes, i understand what you mean. – Ares Nov 11 '21 at 12:45
  • If the requests are independent then you could use the `forkJoin` function. Other than that I don't understand the question quite clearly. – ruth Nov 11 '21 at 12:46
  • i have an extra question , i want to execute the first observable only once and then use it every time .then i execute it in the constructor and pass a reference to fork join, is it correct?? – Ares Nov 11 '21 at 12:55
  • @Ares: Better way to share the response from the observable is to use `shareReplay` operator. See [this post](https://stackoverflow.com/q/36271899/6513921) for more information about it. – ruth Nov 11 '21 at 13:13