0

I'm making a app for myself that should cover "real world" scenarios. I am currently trying to use the Material Autocomplete in a form so that when a user adds/inserts a value to the input the keyup event calls a method that makes an API call that returns some data and I use this to populate an Autocomplete (I have 3 in my page). What I have works but

a) it feels very inefficient

b) Not the best implementation (or the Angular way and

c) it is missing a debounce to prevent the user overloading the server with API calls.

Here I have my form from my HTML template with 3 input that all have a method that captures the keyup event. Each input has a mat-autocomplete in it that iterates through values that match the user input (so if the user inputs "Col" in the company input values like "Cola Inc", "Columbia University", "Color Clothing Inc").

<form novalidate [formGroup]="assignmentForm">
  <div>
    <input type="text" matInput placeholder="User" formControlName="worker" name="worker" (keyup)="getTags($event)" [matAutocomplete]="workerTemplate">
    <mat-autocomplete #workerTemplate="matAutocomplete">
      <mat-option *ngFor="let worker of workerTags" [value]="worker">{{ worker.displayName}}</mat-option>
    </mat-autocomplete>
  </div>

  <div>
    <input type="text" matInput placeholder="Company" formControlName="company" name="company" (keyup)="getTags($event)" [matAutocomplete]="companyTemplate">
    <mat-autocomplete #companyTemplate="matAutocomplete">
      <mat-option *ngFor="let company of companyTags" [value]="company">{{company.displayName}}</mat-option>
    </mat-autocomplete>
  </div>

  <div>
    <input type="text" matInput placeholder="Department" formControlName="department" name="department" (keyup)="getTags($event)" [matAutocomplete]="departmentTemplate">
    <mat-autocomplete #departmentTemplate="matAutocomplete">
      <mat-option *ngFor="let department of departmentTags" [value]="department">{{department.displayName}}</mat-option>
    </mat-autocomplete>
  </div>
</form>

This is the method that takes the user input and calls the API then populates the correct mat-option array (I've reduced a lot of my component code for ease of reading)

        public companyTags: any[];
        public departmentTags: any[];
        public workerTags: any[];

        constructor(private apiService: ApiService) {}

        public getTags(ev: KeyboardEvent): void {
        // if the user presses backspace the value is "" and all results are returned (to set limit)
        if((<HTMLInputElement>ev.target).value !== '') {
    // the api method takes 3 args type, value and limit, it returns an object array         
    this.apiService.getTags((<HTMLInputElement>ev.target).name, (<HTMLInputElement>ev.target).value, 3).subscribe((res) => {
            this.clearAllTags();
            // as the target name is used in the tag array name we can use interpolation
            // rather than a horrible if then else
            this[`${(<HTMLInputElement>ev.target).name}Tags`] = res;
          });
        } else {
          this.clearAllTags();
        }
      }

      /**
       * Clear all specific Tag Arrays
       */
      public clearAllTags(): void {
        this.companyTags = null;
        this.departmentTags = null;
        this.workerTags = null;
      }

I'm wondering the following: Firstly, can I make the form more streamlined by using the AutoComplete once or sharing it between the three inputs as I only show one autocomplete at once time? Secondly how do I use or introduce a debounce here? Should I be using RxJS and Observables and if so should I have 3 Observables or can I listen / subscribe to all three inputs using one Observable? I've done some reading on this but I am a little confused.

If my question seems badly worded please state so and I shall rewrite my question. I am wanting to learn Angular the best way. Many thanks for taking the time to help me.

nircraft
  • 8,242
  • 5
  • 30
  • 46
NewToAngular
  • 975
  • 2
  • 13
  • 23
  • I use the first result to the search for 'javascript debounce function'. But it's basically just a setTimeout. – Shilly Mar 12 '19 at 14:47
  • 1
    See https://stackoverflow.com/questions/41935424/how-to-achieve-a-debounce-service-on-input-keyup-event-in-angular2-with-rxjs/41965515 – mcgraphix Mar 12 '19 at 14:53

0 Answers0