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
我在表单上有两个下拉菜单。当我单击该字段时,静态数组下拉列表(任务)显示完整列表。 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