1

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?

3
  • N.B: This is a multi-dropdown box (4) that comes dynamically from database. If I select 2 from one dropdown and 2 from the other, it gets triggered four times and calls the controller with the same no. Commented Oct 18, 2024 at 22:10
  • If I understood correctly, you want to call setLogData only after about 10s and if there's something changed in the dropdown? So, when it runs, you won't run it again until the described situation reoccurs? Commented Oct 19, 2024 at 8:24
  • Yes @Misha Mashina. There are four dropdown boxes and they have a single event attached to them as you can see in the code sample - (selectionChange)="someMethod($event.value, filter.VAL)". I may select values from them at a time or a value from a single dropdown box. But it should be triggered once for the service after 10 secs. For now, if I change something or select values in the dropdown boxes, it instantly gets triggered that I don't want. Commented Oct 19, 2024 at 9:19

2 Answers 2

2

Ok, so this is a concept of a possible solution:

  1. Introduce new variables on class-level:
  • intervalCallsService: (interval) set to null;
  • newSelectedData: Set, array or object (depending on what is the type of value selected in dropdowns);
  1. Create callServiceAndHandleData method:
  • first it will call the service with newSelectedData as parameter,
  • then it will clear the newSelectedData (or set it to null),
  • and finally it will set intervalCallsService to null;
  1. Dropdown changed method:
  • the received value will be added to newSelectedData [see at the bottom: important];
  • check if intervalCallsService is null: if it is, start it (set it to interval with 10s that will call callServiceAndHandleData method;

So, this is the scenario:

  1. You change the dropdown value, the new value is added to newSelectedData (atm it is the first and only element) and since it's the first time dropdown has changed, it will trigger intervalCallsService (will create interval).

  2. Interval starts running/counting.

  3. If dropdown is changed again, newSelectedData will get another element, but since intervalCallsService is not null, it won't be started again.

  4. When interval hits the end of the count, it will trigger callServiceAndHandleData method, which will send newSelectedData through service, nullify the intervalCallsService and clear newSelectedData.

  5. So when user changed dropdown value again, go to 1.

Important: add new value to newSelectedData only if it's not already there: if values are primitive, Set would be better choice than array, but if it's not a primitive then the object would be better choice and if you are not going completely dynamic - you can have object keyes that correspond to each dropdown, so that you can be sure that each dropdown's value will be added only once as a value of corresponding key.

Sign up to request clarification or add additional context in comments.

2 Comments

Edit: depending on your use-case, if you need to call service only if all dropdowns have a value selected, or if any combination is necessary and you don't want to call the service until conditions are met, simply add that condition together with check of the interval==null
I got the solution @Misha Mashina. Thanks for your suggestion.
1

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();
} 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.