Search code examples
angulartypescriptdom-eventsangular8angular-event-emitter

How to interrupt previous emits with the same event in Angular 8


I have an app that refreshes a datagrid table every time the user selects a row in the table. To make it simple here I have a sample code:

child-component.ts

public jsonData = {...} //api request

this.rowSelectedEvent.subscribe(() => {
  this.refreshData(this.jsonData) 
})

function refreshData(jsonData){
  this.httpService.post(`${environment.BASE_URL}/api`, jsonData.payload).subscribe(
    result => {
      this.resultData = result.data
    }, 
    err => {
      console.error(err)
    }
  )
}

The rowSelectedEvent is triggered in the HTML when the user clicks on a row of a table. This would be an example:

app.component.html

<table>
  <row (click)="notifyRowSelected"></row>
</table>

app.component.ts

@Output() rowSelectedEvent: EventEmitter<string> = new EventEmitter();

[...]

function notifyRowSelected(){
  this.rowSelectedEvent.emit()
}

This code works fine, receives the API response with the new data, it lasts around 4-5 seconds that the server side make its calculations and returns the new values. The problem appears when the user clicks on a few rows repeatedly or in a small amount of time because the app goes crazy and refreshes the data multiple times instead of one time (the last one). I tried using unsubscribe() but then I'm not able to subscribe again so the functionality is lost. I've also tried switchMap() but for some reason when I debug the code it doesn't get into it.

The idea is to stop the pending processes when the user clicks on a new row letting just the last click being the one that make the calculations and receives the response. Any advice?


Solution

  • you could use the power of rxjs to handle that

    private makeCall(data) {
      return this.http.post(...);
    }
    this.rowSelectedEvent.pipe(
       map(() => this.jsonData),
       distinctUntilChanged(), // to skip the same events in a row
       switchMap((data) => this.makeCall(data)),
    ).subscribe((result) => this.resultData = result.data)
    

    all the required power lies in switchMap operator. Whenever new event comes it cancels the previous subscription(you will see canceled red request in a network tab if it is not complete yet) and handler inside of a subscribe will only receive the last event