使 mat-autocomplete 功能像引导选择一样

问题描述 投票:0回答:1

我正在 Angular 中开发一个应用程序,我主要使用 ng-select 来搜索可搜索的下拉菜单,它的工作方式就像一个魅力。现在我正在将整个应用程序迁移到角度材料,并且我面临着一个问题,试图使角度材料垫自动完成工作就像 ng-select 一样。

之前,在编辑现有数据时使用 ng-select 时,我只需要做一个 patchValue 并将选项值设置到控制器中,即可使其相应的标签出现在相应的 ng-select 中。这是 select 的默认行为。当迁移到 mat-autocomplete 时,它不会像这样工作。我知道我可以使用 mat-select 代替,但搜索功能对我来说是关键。

我已经浏览了角度材料文档,并通过使用

displayWith
属性,我能够进行 mat-autocomplete 工作,但我必须将整个选项对象修补到表单控件中,这不是我想要的后端并不是为了以这种方式处理它而开发的。

为了让您了解我在说什么,下面是该场景的示例代码:

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>

打字稿:

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

在上面的代码中,您可以看到,对于引导选择,我只需修补选项的值,选择会自动选择其相应的标签并显示它。但 mat-autocompelete 的情况并非如此。我必须设置整个对象才能正常工作。如果我选择一个选项并单击提交按钮,也会发生同样的事情。 bootstrap select 将控件设置为值,但 mat-autocomplete 将其设置为整个选定的水果对象(我猜这是预期的,因为这是提供给

mat-option
[value]
属性绑定的内容)。

我已经尝试了一些

mat-option
[value]
属性绑定和
displayFn
实现,但没有任何效果。当我使用
fruit.value
进行
[value]
属性绑定时,表单控件会使用所选值而不是整个所选对象进行正确更新,但不会显示标签。

注意:请注意,我可以以相同的形式拥有多个 mat-autocomplete,所有这些都引用不同的数据(但选项结构对于所有数据都是相同的)

angular typescript angular-material
1个回答
0
投票

您可以通过基于

displayFn
数组中的
value
进行搜索来修改
fruits
以显示所选选项的标签。请注意,您需要将其更改为箭头函数才能访问组件变量。

displayFn = (value: string) => {
  if (Number.isNaN(value)) return value;

  return (
    this.fruits?.find((fruit) => fruit.value === Number(value))?.label ||
    value
  );
};

在您看来,将

fruit.value
应用于
[value]
属性。

<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
  @for (fruit of fruits; track fruit.value) {
    <mat-option [value]="fruit.value">{{ fruit.label }}</mat-option>
  }
</mat-autocomplete>

演示@StackBlitz

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.