angulartypescriptangular15

Selecting Multiple Values Should Trigger Service Once With Interval


I've a material drop down box as follows with a select event (selectionChange):

<mat-select #segmentSelector [formControlName]="filter.VAL" multiple placeholder="Select" (selectionChange)="someMethod($event.value, filter.VAL)">
     <div class="custom-panel">
         <ng-container *ngFor="let option of getFilterDropdownOptions(filter.VAL)">
             <mat-option *ngIf="!!option"  [value]="option" [value]="option">
                 {{ option }}
             </mat-option>
         </ng-container>
     </div>
     <footer class="select-box-footer">
         <a class="select-box-footer-btn" (click)="$event.preventDefault();segmentSelector.close();">Done</a>
     </footer>
 </mat-select>

This works fine as it gets triggered whenever I change the value in the dropdown as follows:

someMethod(val: any, columnName: any) {
console.log(val);

    var obj = val as [];

    if (columnName === "CUST_ID") {
      this.aLogData.customerId = [];

      for (var i = 0; i < obj.length; i++) {
        console.log(obj[i]);

        this.aLogData.customerId.push(obj[i]);
      }
    }

    if (columnName === "CUST_NAME") {
      this.aLogData.customerName = [];

      for (var i = 0; i < obj.length; i++) {
        console.log(obj[i]);

        this.aLogData.customerName.push(obj[i]);
      }
    }

    var searchLocationInput = ((document.getElementById("searchLocationInput") as HTMLInputElement).value);
    console.log(this.aLogData);
    console.log(searchLocationInput);

    this.aLogData.searchItem = searchLocationInput;
    this.statusTwo = true;

    setTimeout(() => this.delaySomeMthod(this.aLogData), 10000); //Trying to delay to send data once
  }

  delaySomeMthod(aLogData: LogData) {
    console.log("Called after 10 secs.");
    this.locationService.setLogData(aLogData).subscribe();
  } 

Now the issue is whenever I select or change data in the dropdown it gets triggered and calls the controller each time. I was trying to put a timer to make that work but seems like I require to check to send the request to the controller once and at a certain time interval.

So my requirement is select or change values with dropdown box multiple times, but call the service or controller once after a certain time say 10 secs as I am adding data in an array. Is it something doable?


Solution

  • You can simply write a decorator to perform this action. The method will not fire until the stipulated time has passed. you can keep it in a separate TS file and use it throughout your application (great for reusability).

    export function ngDebounce(timeout: number) {
      // store timeout value for cancel the timeout
      let timeoutRef = null;
    
      return function(target, propertyKey: string, descriptor: PropertyDescriptor) {
        // store original function for future use
        const original = descriptor.value;
        // override original function
        descriptor.value = function(...args) {
          // clear previous timeout
          clearTimeout(timeoutRef);
          // sechudle timer
          timeoutRef = setTimeout(() => {
            // call original function
            original.apply(this, args);
          }, timeout);
        }
        // return descriptor with new value
        return descriptor;
      }
    }
    

    How to implement debounce decorator?

    Usage:

    @ngDebounce(10000)
    delaySomeMthod(aLogData: LogData) {
      console.log("Called after 10 secs.");
      this.locationService.setLogData(aLogData).subscribe();
    }