Skip to content

Instantly share code, notes, and snippets.

@jyotendra
Last active Sep 8, 2018
Embed
What would you like to do?
Implementing throttling on button click

Why throttling is important ?

Throttling enables you to disable input from an stream for a certain period of time, after first event. Example: You might want to call a submit button once - even after multiple clicks by a user. Or you might only want to call an api once after several keystrokes by user - as is case with "type as you search". Limiting API call on every user interaction saves you server side resources and also enhance user experience.

What you can do ?

You can either disable the button or field from taking in more user inputs. But that's not elegant.

Much elegant way .....

Better way would be to create stream of event for every user interaction and then apply plethora of operators that RxJs provides. Most important operator would be "throttleTime". Below is an example, using angular.

In HTML file a subject has been created that launches event - "submit" on every button click. On component (TS) side, this stream is throttled and post that onSubmit() process is called.

Note that writing: <button type="button" (click)="onSubmit()" class="btn btn-primary">Save changes</button> and in onSubmit calling:

onSubmit() {
    if (this.messageForm.valid) {
      const group_id = this.groupDetails.id;
      if (group_id) {
        const formObject = this.messageForm.value;
        formObject.group_id = group_id;
        this.templateService
          .createNewMessage(formObject)
          .subscribe({
            next: res => {
              this.closeModal();
              this.messageForm.reset({
                title: "",
                message_type: "text",
                option_type: "na",
                message_by: "bot"
              });
              this.templateService.refreshMessageList();
              this.toaster.Success("Message added successfully");
            }
          });
      }
    }
  }

This WOULDN'T have worked as on every button click - onSubmit would have created a separate stream, on which throttle would not work. As throttling is practically possible on a continuous stream and can't be applied on every new stream.

<div class="modal" id="message_modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add Message</h5>
<button type="button" class="close" data-dismiss="modal">
<span>×</span>
</button>
</div>
<div class="modal-body">
<form [formGroup]="messageForm" class="">
<div class="form-group">
<label>Message</label>
<input formControlName="title" type="email" class="form-control" placeholder="Enter message"> </div>
<div class="form-group">
<label>Message Type</label>
<select formControlName="message_type" class="form-control" id="select-type">
<option value="text">Text</option>
<option value="option">Option</option>
</select>
</div>
<div class="form-group">
<label for="exampleInputEmail1">Option Type</label>
<select formControlName="option_type" class="form-control">
<option value="na">NA</option>
<option value="single">Single</option>
<option value="multiple">Multiple</option>
</select>
</div>
<div class="form-group">
<label for="exampleInputEmail1">Messenger</label>
<select formControlName="message_by" class="form-control">
<option value="bot">Bot</option>
<option value="user">User</option>
</select>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" (click)="buttonEvent$.next('submit')" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
import { Component, OnInit } from "@angular/core";
import { FormGroup, FormBuilder, Validators } from "@angular/forms";
import { TemplateService } from "@app/template/template.service";
import { group } from "@angular/animations";
import { ToasterService } from "@app/shared/services/toaster.service";
import { debounceTime, filter, throttleTime } from "rxjs/operators";
import { Subject } from "rxjs";
declare const $;
@Component({
selector: "app-group-add-message-modal",
templateUrl: "./add-message.component.html"
})
export class AddMessageComponent implements OnInit {
messageForm: FormGroup;
groupDetails: any;
buttonEvent$ = new Subject();
constructor(
private fb: FormBuilder,
private toaster: ToasterService,
private templateService: TemplateService
) {
this.messageForm = this.fb.group({
title: [
"",
Validators.compose([Validators.required, Validators.minLength(1)])
],
message_type: ["text", Validators.required],
option_type: ["na", Validators.required],
message_by: ["bot", Validators.required]
});
}
ngOnInit() {
this.templateService.gotGroupDetail$.subscribe({
next: grp => {
this.groupDetails = grp;
}
});
this.buttonEvent$
.pipe(
filter(e => e === "submit"),
throttleTime(5000)
)
.subscribe(() => {
this.onSubmit();
});
}
closeModal() {
$("#message_modal").modal("hide");
}
onSubmit() {
if (this.messageForm.valid) {
const group_id = this.groupDetails.id;
if (group_id) {
const formObject = this.messageForm.value;
formObject.group_id = group_id;
this.templateService
.createNewMessage(formObject)
.subscribe({
next: res => {
this.closeModal();
this.messageForm.reset({
title: "",
message_type: "text",
option_type: "na",
message_by: "bot"
});
this.templateService.refreshMessageList();
this.toaster.Success("Message added successfully");
}
});
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment