1

this.filteredContact = this.contactControl.valueChanges.pipe(
  startWith(''),
  debounceTime(200),
  map(val => this.filterContact(val))
);

filterContact(val: string): any {
  if (val.length > 2) {
    return _.filter(
      this.contacts,
      item => item.name.toLowerCase().indexOf(val.toLowerCase()) !== -1
    );
  }
}

this.filteredContact = this.contactControl.valueChanges.pipe(
  startWith(''),
  debounceTime(200),
  switchMap(
    val =>
    val.length > 2 ?
    _.filter(
      this.contacts,
      item => item.name.toLowerCase().indexOf(val.toLowerCase()) !== -1
    ) :
    Observable.of([])
  ),
  map(result => result.contacts)
);

I am using Angular materialAutoComplete field where service call pulls data as the user keys in. As the user types faster than the service pulls the data, there is no sync in what is actually displayed in the autocompleteSelection panel. How to achieve a perfect data in materialAutoComplete. How to match/overcome the speedness of user tying in the field and the output fetched from service to display in the autocompletePanel?

public filteredCustomersByName: Observable<e.ICustomer[]>;

    this.filteredCustomersByName = this.customerNameControl.valueChanges.pipe(
      startWith(''),
      debounceTime(200),
      map(val => this.filterCustomersByName(val))
    );


  filterCustomersByName(val: string): any {
    if (val.length > 2) {
      this.appData.get(this.appData.url.getCustomerByName, [val]).subscribe(
        result => {
          this.customersByName = result.customers;
        },
        err => {
          console.log('Error ' + err.message);
          this.toastr.error(err.message);
        }
      );
      return this.customersByName;
    }
  }
            <div class="box-row">
              <mat-form-field>
                <input placeholder="Customer Name" type="text" #customerNameId matInput [formControl]="customerNameControl" [(ngModel)]='selectedCustomerName'
                  [matAutocomplete]="customerName" required>
                <mat-autocomplete #customerName="matAutocomplete" class='customerDetails'>
                  <mat-option (click)="setCustomerDetails(customer)" *ngFor="let customer of filteredCustomersByName | async" [value]="customer.name">
                    {{ customer.name}}
                  </mat-option>
                </mat-autocomplete>
              </mat-form-field>
            </div>

Thanks in advance.

 filterCustomerByCode(val: string): any {
    if (val.length > 2) {
      if (val.charAt(0).toLowerCase() !== 'b') {
        val = ('000000000000' + val).substr(-10);
      }
      this.appData.get(this.appData.url.getCustomerByCode, [val]).subscribe(
        result => {
          this.customersByCode = result.customers;
        },
        err => {
          console.log('Error ' + err.message);
          this.toastr.error(err.message);
        }
      );
      return this.customersByCode;
    }
  }

I tried changing the filteredContact using switchMap, please check and let me know why am getting error at result.contacts in the statement map(result => result.contacts)

Sundar
  • 655
  • 2
  • 7
  • 13

1 Answers1

1

Try using switchMap. It will make sure that the result is always fresh.

On each emission the previous inner observable (the result of the function you supplied) is cancelled and the new observable is subscribed

filteredCustomersByName

this.filteredCustomersByName = this.customerNameControl.valueChanges.pipe(
  startWith(''),
  debounceTime(200),
  switchMap(val => val.length > 2 
      ? this.appData.get(this.appData.url.getCustomerByName, [val])
      : of([])
 ),
  map(result => result.customers)
);

filterCustomerByCode

this.filterCustomerByCode = this.customerNameControl.valueChanges.pipe(
  startWith(''),
  debounceTime(200),
  switchMap((val: string) => {
    if (val.length > 2 || val.charAt(0).toLowerCase() === 'b') {
      const mappedVal = ('000000000000' + val).substr(-10);
      return this.appData.get(this.appData.url.getCustomerByName, [mappedVal]);
    }
    return of([]);
  }),
  map(result => result.customers)
);
Tomasz Kula
  • 16,199
  • 2
  • 68
  • 79
  • Thanks the above answer is helpful. I have used observable.Of() in the above code and it works. I also have similar code as filterCustomerByCode. Could you help to restructure in above format . – Sundar Apr 12 '18 at 12:22
  • Thanks, I will validate and confirm, how it works. You are greatly helpful. – Sundar Apr 12 '18 at 12:46
  • Could you please take a look at below link and if possible try to solve the same. I am struck in dynamic multiple rows with some of the columns blank using angular material data table. https://stackoverflow.com/questions/49774579/angular-material-data-table-with-dynamic-rows/49774886?noredirect=1#comment86592559_49774886 – Sundar Apr 12 '18 at 12:48
  • I tried changing the filteredContact using switchMap, please check and let me know why am getting error at result.contacts in the statement map(result => result.contacts) Please help me with this as well. Thanks again. – Sundar Apr 13 '18 at 01:54
  • In this filteredContact there is no filter in the service, so once the data arrives, we need to filter matching the letters typed in and show the results in autoComplete Panel. – Sundar Apr 13 '18 at 06:05