我正在用Angular开发一个应用程序,我主要使用它
<ng-select>
对于可搜索的下拉菜单,它就像一个魅力。现在我正在将整个应用程序迁移到Angular Material,我遇到了一个问题,试图让Angular Material mat自动完成,就像一个
<ng选择>
.
早些时候,当使用
<ng选择>
编辑现有数据时,我只需要做一个
patchValue
并将选项值设置到控制器中,使其相应的标签出现在其相应的
<ng选择>
。这是select的默认行为。迁移到时
<mat-autocomplete>
它不是这样工作的。我明白我可以使用
<mat-select>
相反,搜索功能对我来说是关键。
我已经阅读了Angular Material文档,并使用了
displayWith
我可以创造的财产
<垫子自动补全>
工作。尽管如此,我必须将整个选项对象修补到表单控件中,这不是我想要的,因为我的后端不是这样开发的。
为了让你了解我在说什么,下面是场景的示例代码:
HTML:
<form [formGroup]="fruitFormBootstrap">
<div class="row">
<div class="col-4">
<label for="fruits" class="form-label">Fruits</label>
<select id="fruits" class="form-select" formControlName="fruit">
@for (fruit of fruits; track $index) {
<option [value]="fruit.value">{{ fruit.label }}</option>
}
</select>
</div>
</div>
<div>
<button class="btn btn-primary" (click)="submitBootstrapForm()">Submit</button>
</div>
</form>
<hr>
<form [formGroup]="fruitFormMaterial">
<mat-form-field class="example-full-width">
<mat-label>Fruits</mat-label>
<input type="text"
placeholder="Pick one"
aria-label="Fruits"
matInput
formControlName="fruit"
[matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
@for (fruit of fruits; track fruit.value) {
<mat-option [value]="fruit">{{fruit.label}}</mat-option>
}
</mat-autocomplete>
</mat-form-field>
<button mat-raised-button (click)="submitAngularMaterialForm()">Submit</button>
</form>
TypeScript:
import {Component, OnInit} from '@angular/core';
import {MatInputModule} from "@angular/material/input";
import {MatAutocompleteModule} from "@angular/material/autocomplete";
import {FormBuilder, FormControl, FormGroup, ReactiveFormsModule} from "@angular/forms";
import {MatFormFieldModule} from "@angular/material/form-field";
import {MatButtonModule} from "@angular/material/button";
import {MatListModule} from "@angular/material/list";
import {MatSelectModule} from "@angular/material/select";
@Component({
selector: 'app-root',
standalone: true,
imports: [
MatFormFieldModule,
MatInputModule,
MatAutocompleteModule,
MatSelectModule,
ReactiveFormsModule,
MatButtonModule,
MatListModule
],
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent implements OnInit {
fruits: Array<{ value: number, label: string }>;
fruitFormBootstrap: FormGroup;
fruitFormMaterial: FormGroup;
constructor(private fb: FormBuilder) {
this.fruits = [
{ value: 1, label: 'Watermelon' },
{ value: 2, label: 'Apple' },
{ value: 3, label: 'Banana' }
];
this.fruitFormBootstrap = this.fb.group({
fruit: new FormControl()
});
this.fruitFormMaterial = this.fb.group({
fruit: new FormControl()
});
}
// Patching a value in bootstrap automatically selects its corresponding label for display
ngOnInit() {
this.fruitFormBootstrap.patchValue({
fruit: 2
});
//angular material autocompelte patching only updates the controller without updating the display to show its corresponding label
// this.fruitFormMaterial.patchValue({
// fruit: 2
// });
const searchFruit = this.fruits.find(fruit => fruit.value === 2);
//although this works but it sets the entire object as form control value which is not what I want
this.fruitFormMaterial.patchValue({
fruit: searchFruit
})
}
//submitting a select in bootstrap set the form control with the value of the selected option
submitBootstrapForm() {
console.log(this.fruitFormBootstrap);
}
//Based on angular material documentation this is how to have a separate display value than the control
displayFn(option: { value: number, label: string }) {
return option ? option.label : '';
}
submitAngularMaterialForm() {
console.log(this.fruitFormMaterial);
}
}
在上面的代码中,您可以看到Bootstrap的选择。我只需要修补选项的值,选择就会自动选择相应的标签并显示出来。但事实并非如此
<mat-autocompelete>
。我必须设置整个对象才能正常工作。如果我选择一个选项并单击提交按钮,也会发生同样的事情。Bootstrap select正在将控件设置为值,但
<垫子自动补全>
将其设置为整个选定的水果对象(我想这是意料之中的,因为这是提供给
mat-option
[value]
财产约束)。
我玩过一段时间
垫子选项
[价值]
财产约束和
displayFn
实施,但没有任何效果。当我使用
fruit.value
对于
[价值]
绑定表单控件的属性会使用所选的值而不是整个所选对象进行正确更新,但标签不会显示。
注意:只需注意,我可以有多个
<垫子自动补全>
(s) 在相同的形式中,所有引用不同的数据(但选项结构对所有都是相同的)
编辑:
感谢YongSun的回答,它奏效了!但我想我应该提供更多关于我面临的挑战的细节
<垫子自动补全>
(s) 以同样的形式。道歉。所以,我有多个
<垫子自动补全>
(s) 在后端返回的JSON动态生成的表单中,表单如下:
<form [formGroup]="dataForm">
<div formArrayName="forms">
@for (form of getForms(); track $index) {
<div [formGroupName]="$index">
@for (field of fieldsArray; track $index) {
@if (field.display) {
@switch (field.type) {
@case ('input') {
@switch (field.inputType) {
@case ('text') {
<mat-form-field appearance="outline" class="w-50 pb-2 pe-2">
<mat-label>{{ field.displayName }}</mat-label>
<input type="text" matInput [formControlName]="field.controllerName">
</mat-form-field>
}
@case ('number') {
<mat-form-field appearance="outline" class="w-50 pb-2">
<mat-label>{{ field.displayName }}</mat-label>
<input type="number" matInput [formControlName]="field.controllerName">
</mat-form-field>
}
@case ('date') {
<mat-form-field appearance="outline" class="w-50 pb-2 pe-2">
<mat-label>{{ field.displayName }}</mat-label>
<input matInput [matDatepicker]="picker" [formControlName]="field.controllerName">
<mat-hint>MM/DD/YYYY</mat-hint>
<mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
}
@case ('checkbox') {
<mat-checkbox [formControlName]="field.controllerName">{{ field.displayName }}</mat-checkbox>
}
}
}
@case ('textarea') {
<mat-form-field appearance="outline" class="w-100 pb-2 pe-2">
<mat-label>{{ field.displayName }}</mat-label>
<textarea matInput [formControlName]="field.controllerName"></textarea>
</mat-form-field>
}
@case ('select') {
<mat-form-field class="w-50 pb-2 pe-2" appearance="outline">
<mat-label>{{ field.displayName }}</mat-label>
<input type="text"
placeholder="Pick one"
matInput
[formControlName]="field.controllerName"
[matAutocomplete]="auto">
<mat-autocomplete requireSelection #auto="matAutocomplete" [displayWith]="displayFn">
@for (option of filteredOptions.get(field.controllerName)! | async; track option) {
<mat-option [value]="option">{{ option.label }}</mat-option>
}
</mat-autocomplete>
</mat-form-field>
}
}
}
}
</div>
}
</div>
</form>
因此,尽管
显示器Fn
Yong-Shun在回答中提供的实现是正确的,但我很难弄清楚如何通过
formControlName
更改了该选项,以便我可以在从中获取选项值列表值后执行查找操作
filteredOptions
地图与
表单控制名称
:
filteredOptions: Map<string, Observable<Option[]>>;