Вызов полевой службы Angular materialAutoComplete извлекает данные медленнее, чем пользователь вводит в

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

Я использую поле Angular materialAutoComplete, где вызов службы извлекает данные по мере того, как пользователь вводит их. Поскольку пользователь вводит данные быстрее, чем служба извлекает данные, синхронизация того, что фактически отображается на панели autocompleteSelection, отсутствует. Как добиться идеальных данных в materialAutoComplete. Как сопоставить/превзойти скорость привязки пользователя к полю и вывод, полученный из службы, для отображения в 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>

Заранее спасибо.

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

Я попытался изменить filteredContact с помощью switchMap, пожалуйста, проверьте и дайте мне знать, почему я получаю сообщение об ошибке в result.contacts в карте операторов (result => result.contacts)


person Sundar    schedule 12.04.2018    source источник


Ответы (1)


Попробуйте использовать switchMap. Это позаботится о том, чтобы результат всегда был свежим.

При каждом излучении предыдущая внутренняя наблюдаемая (результат предоставленной вами функции) отменяется, а новая наблюдаемая подписывается

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

фильтрацияCustomerByCode

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)
);
person Tomasz Kula    schedule 12.04.2018
comment
Спасибо, приведенный выше ответ полезен. Я использовал observable.Of() в приведенном выше коде, и он работает. У меня также есть код, аналогичный filterCustomerByCode. Не могли бы вы помочь реструктурировать в вышеуказанном формате. - person Sundar; 12.04.2018
comment
Спасибо, я проверю и подтвержу, как это работает. Вы очень помогаете. - person Sundar; 12.04.2018
comment
Не могли бы вы взглянуть на ссылку ниже и, если возможно, попытаться решить то же самое. Я поражен динамическими несколькими строками с некоторыми пустыми столбцами, используя таблицу данных угловых материалов. stackoverflow.com/questions/49774579/ - person Sundar; 12.04.2018
comment
Я попытался изменить filteredContact с помощью switchMap, пожалуйста, проверьте и дайте мне знать, почему я получаю сообщение об ошибке в result.contacts в карте операторов (result => result.contacts). Пожалуйста, помогите мне и с этим. Спасибо еще раз. - person Sundar; 13.04.2018
comment
В этом filteredContact в сервисе нет фильтра, поэтому, как только данные поступят, нам нужно отфильтровать соответствие введенным буквам и показать результаты в панели автозаполнения. - person Sundar; 13.04.2018