мат-автозаполнение без фильтрации с помощью наблюдаемых

#angular #observable #mat-autocomplete

Вопрос:

У меня есть два раскрывающихся списка автозаполнения мата в реактивной угловой форме (Угловой и угловой материал v12).

Один работает. Он извлекает массив объектов из службы и не включает в себя наблюдаемое для параметров. Он разработан аналогично приведенному примеру. Другой подписывается на наблюдаемый для выпадающих вариантов, и они отображаются, но не могут фильтроваться. Я не вижу ошибок.

Моя гипотеза заключается в том, что либо фильтр срабатывает до того, как появляются данные, либо существует какая-то другая проблема с тем, как применяется фильтр. Данные отображаются просто отлично — я просто не могу печатать и фильтровать.

Я настроил наблюдаемый код немного по-другому, чтобы разрешить подписку на API для запуска до подписки на фильтр и для сравнения уникального идентификатора. Похоже, это не сработало. Я не могу определить, какая часть кода выходит из строя. Я попытался повторить рабочий код с наблюдаемым, но он не может фильтровать тип таким же образом (принимает два аргумента), и я застрял там.

Может быть, есть способ упростить мою подписку? Я понимаю, что происходит, но мой наблюдаемый опыт-это свет. Соответствующий код ниже:

Рабочий шаблон:

 <mat-grid-tile-header>
    Waste Type
</mat-grid-tile-header>
   <mat-form-field appearance="standard">
      <mat-label>Waste Type</mat-label>
         <input
            tabindex="2"
            #waste_type
            matInput
            [matAutocomplete]="waste_type_auto"
            placeholder="Choose a Waste Type"
            class="input"
            type="text"
            formControlName="waste_type"
            [ngClass]="{'is-success' : collectForm.get('waste_type').valid amp;amp; collectForm.get('waste_type').dirty, 'is-danger' : !collectForm.get('waste_type').valid }"
             aria-label="Waste Type">
             <mat-autocomplete #waste_type_auto="matAutocomplete">
                <mat-option *ngFor="let waste_type of filteredWaste_Types$ | async" [value]="waste_type.name">
                <img class="example-option-img" aria-hidden [src]="waste_type.icon" height="25">
                <span>{{ waste_type.name }}</span>
                </mat-option>
             </mat-autocomplete>
             <mat-hint [hidden]="collectForm.get('waste_type').valid" align="end">Waste type (e.g., Recycling) is required</mat-hint>
              </mat-form-field>
 

Нерабочий шаблон (практически тот же):

 <mat-grid-tile-header>
          Tare
        </mat-grid-tile-header>
            <mat-form-field appearance="standard">
              <mat-label>Waste Container</mat-label>
              <input
              tabindex="4"
              #tare_container
              placeholder="Enter Container"
              matInput
              [matAutocomplete]="tare_auto"
              class="input"
              type="text"
              formControlName="tare_container"
              [ngClass]="{'is-success' : collectForm.get('tare_container').valid amp;amp; collectForm.get('tare_container').dirty, 'is-danger' : !collectForm.get('tare_container').valid }"
               aria-label="Tare Container">
                <mat-autocomplete #tare_auto="matAutocomplete">
                  <mat-option *ngFor="let tare of filteredTares$ | async" [value]="tare.container_name">
                  <img class="example-option-img" aria-hidden [src]="tare.container_icon" height="25">
                  <span>{{ tare.container_name }}</span>
                  </mat-option>
                </mat-autocomplete>
                <mat-hint [hidden]="collectForm.get('tare_container').valid" align="end">Tare (e.g., Lg Compost Bin) is required</mat-hint>
                </mat-form-field>
 

.ts for both filters

 filteredWaste_Types$: Observable<Waste_Type[]>;
filteredTares$: Observable<Tare[]>;

// Working Value Changes Subscription

this.filteredWaste_Types$ = this.collectForm.get('waste_type').valueChanges
        .pipe(
          startWith(''),
          map(value => this._filteredWaste_Types(value))
        );

// Non-Working Value Changes Subscription

this.filteredTares$ = zip(
       this.collectForm.get('tare_container').valueChanges
       .pipe(
         startWith('')),
         this.ts.tares,
        )
        .pipe(
          map(([value, tares]) => {
          const filtered = value ? this._filteredTares(value, tares) : tares;
          return filtered;
        })
      );

// Working Filter

private _filteredWaste_Types(value: string): Waste_Type[] {
    const filterValue = value.toLowerCase();
    return this.wts.waste_types.filter(waste_type => waste_type.name.toLowerCase().includes(filterValue));
}

// Non-Working Filter
    
private _filteredTares(value: string, tares: Tare[]): Tare[] {
     const filterValue = value.toLowerCase();
     return tares.filter(tare => tare.container_name.toLowerCase().includes(filterValue));
}
 

Working waste_type service:

 waste_types: Waste_Type[] = [
  {
    name: 'Batteries',
    icon: './assets/img/battery_icon.png'
  },
  {
    name: 'Cardboard',
    icon: './assets/img/cardboard_icon.png'
  },
  {
    name: 'Compost',
    icon: './assets/img/compost_icon.png'
  }];
 

Нерабочее обслуживание тары:

 public cachedTares: Tare[] = [];
    
public get tares() {
   return this.api.getTares()
   .pipe(
    map((tares) => {
    this.cachedTares = tares;
    return tares;
    })
    );
    };
    
 

API, который обслуживает нерабочую службу:

 public getTares() {
  const uri = '/containers';
  if (this.isOnline) {
    return this.http.get<Tare[]>(uri, this.httpOptions).pipe(
    map(this.cacheGetRequest(uri)),
    );
    } else {
    const result = this.getCachedRequest<Tare[]>(uri);
    return new BehaviorSubject(result).asObservable();
    }
   }
 

Структура данных у каждого из них практически одинакова:

 export interface Waste_Type {
  name: string;
  icon: string;
}

export interface Tare {
  id: number;
  container_name: string;
  container_icon: string;
  container_weight: number;
}
 

Комментарии:

1. есть шанс, что ты сможешь сделать стакблиц?

Ответ №1:

Я думаю, вам просто нужно zip заменить combineLatest оператор rxjs.

Разница в том, что:

Оператор combineLatest ведет себя аналогично zip, но в то время как zip излучает только тогда, когда каждый наблюдаемый источник ранее излучал элемент, combineLatest излучает элемент всякий раз, когда какой-либо из наблюдаемых источников излучает элемент

Это означает, что ваш filteredTares$ наблюдаемый выдает значение только один раз, когда вы получили ответ от TareService . После этого он молчит, даже если valueChanges выдает новые значения(даже когда вы вводите input )

 this.filteredTares$ = combineLatest([
  this.collectForm2.get('tare_container').valueChanges.pipe(startWith('')),
  this.ts.tares,
])
...
 

Пример Стекблитца

Комментарии:

1. Это сработало идеально! Спасибо @yurzui.