Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid multiple http calls on pressing enter button multiple times

I have a button which makes an API call on keyboard enter. If they enter instantly multiple times, it would make 'n' no. of calls.

How to avoid this with a clean generic solution, so that it can be used everywhere?

    <button click="initiateBulkPayment()(keyup.enter)="initiateBulkPayment">

    initiateBulkPayment = (orderId:any, payment_methods:any) => {
       let postParams = payment_methods;
       console.log('this is payment_method', payment_methods);


       return this.http.post(Constants.API_ENDPOINT + '/oms/api/orders/' + 
           orderId + '/payments/bulk_create/', postParams, this.auth.returnHeaderHandler())
          .pipe(map((data: any) => {
           return data;
       }),
       catchError((err)=>{
         return throwError(err);
       }));
   }
like image 262
sharath subramanya Avatar asked Mar 16 '26 18:03

sharath subramanya


1 Answers

There are two solutions:

  1. Disable the button while the call is being executed
  2. Skip the excess calls

Disable the button while the call is being executed:

<button [disabled]="paymentRequest.inProgress$ | async" (click)="onPayButtonClick()">
export class ProgressRequest {
    private _inProgress$ = new UniqueBehaviorSubject(false);

    execute<TResult>(call: () => Observable<TResult>): Observable<TResult> {
        if (!this._inProgress$.value) {
            this._inProgress$.next(true);
            return call().pipe(
                finalize(() => {
                    this._inProgress$.next(false);
                })
            );
        } else {
            throw new Error("the request is currently being executed");
        }
    }

    get inProgress$(): Observable<boolean> {
        return this._inProgress$;
    }
}

@Component({ ... })
export class MyComponent {
    readonly paymentRequest = new ProgressRequest();

    onPayButtonClick() {
        this.paymentRequest.execute(() => {
            return this.http.post(
                Constants.API_ENDPOINT + '/oms/api/orders/' + orderId + '/payments/bulk_create/',
                postParams,
                this.auth.returnHeaderHandler()
            ).pipe(map((data: any) => {
                return data;
            });
        }).subscribe(data => {
            console.log("done!", data);
        });
    }
}

Skip the excess calls:

You can use exhaustMap to skip requests while the previoius one is being executed. Note that switchMap and shareReplay, which was suggested in other answers won't prevent excess http calls.

<button #paymentButton>
@Component({ ... })
export class MyComponent implements OnInit {
    @ViewChild('paymentButton', { static: true })
    readonly paymentButton!: ElementRef<HTMLElement>;

    ngOnInit() {
        merge(
            fromEvent(this.paymentButton.nativeElement, 'click'),
            fromEvent<KeyboardEvent>(this.paymentButton.nativeElement, 'keyup').pipe(
                filter(event => event.key === "Enter")
            )
        ).pipe(
            exhaustMap(() => {
                return this.http.post(
                    Constants.API_ENDPOINT + '/oms/api/orders/' + orderId + '/payments/bulk_create/',
                    postParams,
                    this.auth.returnHeaderHandler()
                ).pipe(map((data: any) => {
                    return data;
                });
            })
        ).subscribe(result => {
            console.log(result);
        });
    }
}

Note that click event is fired also when you press the enter key, so it isn't necessary to listen 'keyup'.

// You can replace
merge(
    fromEvent(this.paymentButton.nativeElement, 'click'),
    fromEvent<KeyboardEvent>(this.paymentButton.nativeElement, 'keyup').pipe(
        filter(event => event.key === "Enter")
    )
)

// just by
fromEvent(this.paymentButton.nativeElement, 'click')
like image 68
Valeriy Katkov Avatar answered Mar 19 '26 08:03

Valeriy Katkov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!