Angular Material 自动完成不显示 API 数据,直到发生字段更改

Angular Material autocomplete not displaying API data until after field change has occurred

我在表单上有两个下拉菜单。当我单击该字段时,静态数组下拉列表(任务)显示完整列表。 API(Driver Manager) 中的对象数组仅当我在该字段中键入字母并退格时才显示完整列表。如何在最初选择该字段时显示 API 筛选选项下拉列表?

import { Component, OnInit, OnChanges } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';
import {Observable} from 'rxjs';
import {map, startWith} from 'rxjs/operators';

import { Drivermanager  } from '../../models/drivermanager.model';
import { DrivermanagerService } from '../../services/drivermanager.service';


@Component({
  selector: 'app-testplatform',
  templateUrl: './testplatform.component.html',
  styleUrls: ['./testplatform.component.scss']
})
export class TestplatformComponent implements OnChanges, OnInit {

  // Statics arrays
  taskOptions = [
    {id:0, name: 'Unassigned'},
    {id:1, name: 'Engineering'},
    {id:2, name: 'Installation'},
    {id:3, name: 'Warehouse'}
  ];

  // Api filled arrays
  drivermanagers: Drivermanager[] = [];
  dmOptions: Drivermanager[] = [];
  filteredDMOptions: Observable<any[]>;

  // Pre-defined arrays
  filteredTaskOptions: Observable<any[]>;

  // Define the FormGroup
  sampleForm: FormGroup = new FormGroup({});

  // Form Controls
  taskControl = new FormControl();
  dmControl = new FormControl();


  constructor(public mservice: DrivermanagerService, private fb : FormBuilder) { }

  ngOnChanges() {
  }

  ngOnInit(): void {
    this.initializeForm();
    this.getDriverManagers();

    this.filteredTaskOptions = this.taskControl.valueChanges.pipe(
      startWith(''),
      map((term) => {
        return this.taskOptions.filter((task) =>
          task.name.toLowerCase().includes(term.toLowerCase())
        );
      })
    );

    this.filteredDMOptions = this.sampleForm.get('fc_dmanager').valueChanges.pipe(
      startWith(''),
      map((term) => {
        return this.dmOptions.filter((dm) =>
          dm.name.toLowerCase().includes(term.toLowerCase())
        );
      })
    );
  }

  initializeForm(){
    this.sampleForm = this.fb.group({
      fc_task: ['', [Validators.required]],
      fc_dmanager: ['', [Validators.required]]
    });
  }

  displayFn(subject) {
    return subject ? subject.name : undefined;
  }

  getDriverManagers() {
    this.mservice.getDriverManagerList().subscribe((data: Drivermanager[]) => {
      this.drivermanagers = data
      console.log('Fetched Driver Manager List');
      this.drivermanagers.sort((a,b) => {
        let fa = a.name.toLowerCase(),
            fb = b.name.toLowerCase();

        if (fa < fb) {
          return -1;
        }
        if (fa > fb) {
          return 1;
        }
        return 0;
      });
      console.log('Sorted dm list - ', this.drivermanagers);
      this.dmOptions = this.drivermanagers;
      console.log('dmOptions - ', this.dmOptions);
    })
  }

  onSubmit() {
    // Do something with that data
  }

  onClear() {
    // Reset the fields on the form
  }
}
<form [formGroup]="sampleForm" (submit)="onSubmit()">
  <div class="container">
    <mat-form-field class="marginright" appearance="outline" [style.width.px]=120 style="font-size: 12px;">
    <mat-label>TASK</mat-label>
    <input matInput [matAutocomplete]="autotask" formControlName="fc_task" style="font-size: 14px;">
    <mat-autocomplete #autotask="matAutocomplete" [displayWith]="displayFn">
      <mat-option [value]="task" *ngFor="let task of filteredTaskOptions | async">
        {{task.name}}
      </mat-option>
    </mat-autocomplete>
  </mat-form-field>
  <!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
  <mat-form-field class="marginright" appearance="outline" [style.width.px]=200 style="font-size: 12px;">
    <mat-label>Driver Manager</mat-label>
    <input matInput [matAutocomplete]="autodm" formControlName="fc_dmanager" style="font-size: 14px;">
    <mat-autocomplete #autodm="matAutocomplete" [displayWith]="displayFn">
      <mat-option [value]="dm" *ngFor="let dm of filteredDMOptions | async">
        {{dm.name}}
      </mat-option>
    </mat-autocomplete>
  </mat-form-field>
  </div>
  <div class="button-row" style="margin: 0; padding: 0;">
    <button mat-raised-button color="primary" type="submit" (click)="onSubmit()">Submit</button>
    <button mat-raised-button color="warn"  (click)="onClear()">Clear</button>
  </div>
</form>

这很可能是竞争条件。当您的 startWith 被触发时,您尝试排序的数组还没有值。你会想要实际附加一个可观察到它,这样你就有了要排序的值。您可以使用 shareReplay 来不多次触发该函数。所以在你的组件中有这样的东西 ts:

dm$ = this.mservice.getDriverManagerList().pipe(
  shareReplay();
);

ngOnInit() {
  // more code...
    this.filteredDMOptions = this.sampleForm.get('fc_dmanager').valueChanges.pipe(
      startWith(''),
      switchMap((term) => {
        return this.dm$.pipe(
          map((dmOptions) => {
            return dmOptions.filter((dm) =>
              dm.name.toLowerCase().includes(term.toLowerCase())
            );
          })
        )
      })
    );
}

在您的模板中,您需要使用 async 管道来订阅数组。

对您的其他列表执行相同的操作。

这是演示:https://stackblitz.com/edit/angular-ivy-ncaa4t?file=src%2Fapp%2Fapp.component.ts