Search code examples
angularrxjsobservablehttpclient

Make sure that the last http post reaches back-end last in Angular


How could I make sure that the last http post reaches back-end last in Angular?

My use case. I have a simple implemented by me chip list. It is represented by chips and an input at the end. When user types something into the input and presses the Enter then a chip with the typed text is added to the chip list, also user can remove a specific chip from the list. On both the addition and removal I am updating the chip list on the back-end. Here is the piece of code responsible for this.

addNewChip() {
    if(this.chipText) {
        this.chips.push(this.chipText);
        this.chipText = "";
        this.updateChipsOnBE();
    }
}

removeChip(chipText) {
    this.chips = this.chips.filter(text => text !== chipText);
    this.updateChipsOnBE();
}

private updateChipsOnBE(): Observable<string[]> {
    return this.chipAPI.update(this.BEAddress, this.chips);
}

Now I am worried about the possible race condition: the this.chipAPI.update operation may not yet be completed on BE, while another this.chipAPI.update operation will be triggered in such a way, that the latter operation will complete before the former. That would mean, that a user would lose the last change he or she applied.

I am feeling that there is should be a way in RxJS to prevent it, but I can not neither find nor come up with a solution.


Solution

  • You need to use concatMap operator inside of chipAPI.

    something like:

    send$ = new Subject();
    
    constructor(http: HttpClient) {
      this.send$.pipe(
        // contact waits until the inner stream has been completted.
        concatMap(([address, chips]) => this.http.post(address, chips).pipe(
          retry(5), // in case of failed request,
          // catchError(() => EMPTY), // perhaps we can ignore errors
        )),
        // takeUntil(this.destroy$), // you need to implement an unsubscribe trigger.
      ).subscribe();
    }
    
    update(address, chips): {
      this.send$.next([address, chips]);
    }