1

I am running into an issue where I would like to modify the objects inside an array based on data returned from a subscription.

this.options = this.options.map(data => {
      this.workflowTemplateService.getWorkflowTemplateStatistics(data.id).subscribe(res => {
        const available = (res.contactsInProgress + res.contactsInWaitingRoom + res.pausedCount).toString();
        const waitingRoomLimit = res.waitingRoomLimit;
        const quota = available.toString() + '/' + waitingRoomLimit.toString();
        console.log("Hit quota: ", quota);
        return {...data, quota};
      });
});

I wanted to do something like this where I would be able to add the quota property to each of the objects inside the array but I am getting an error related to returning void. I was wondering if there were another way where I would able to modify the options such that I can add the quota property into the options array.

2 Answers2

1
this.options$ = of(this.options)
.pipe(
  switchMap(data => this.workflowTemplateService.getWorkflowTemplateStatistics(data.id)),
  map(res => {
    const available = (res.contactsInProgress + res.contactsInWaitingRoom + res.pausedCount).toString();
        const waitingRoomLimit = res.waitingRoomLimit;
        const quota = available.toString() + '/' + waitingRoomLimit.toString();
        console.log("Hit quota: ", quota);
        return {...data, quota};
  })
)

Now you can suscribe directly to this.options$ which is now an observable or you can used directly in the template like options$ | async

this.options$.suscribe(res => console.log(res))
Abel Valdez
  • 2,368
  • 1
  • 16
  • 33
-1

First, you should convert your observable to promise to be able to take the advantage of using async/await. You can convert your observable to promise by using firstValueFrom operator in rxjs to take the first value emitted and close the subscription after that.

const promise = firstValueFrom(this.workflowTemplateService.getWorkflowTemplateStatistics(data.id));

By converting your observable to a promise, now you can mark the map callback function as async. Here is the link about async map callback function:

Best way to call an asynchronous function within map?

and your result would be something like below

async updateOptions() {
   this.options = await Promise.all(
      this.options.map(async data => {
      const result = await firstValueFrom(this.workflowTemplateService.getWorkflowTemplateStatistics(data.id));
      ...
      return {...data, quota};
      })
   )
}
mahyar
  • 49
  • 1
  • 2
  • Using promises inside of RxJS operators is surely a red flag. It's so easy to introduce bugs that way (they have different execution semantics). Using promises inside an RxJS `map` operator is doubly bad. `Map` is meant to synchronously apply some transformation to each value, you can use higher order operators to map into async values – Mrk Sef Dec 09 '21 at 02:18