如何为多字段(至少10个)复用Angular Material Autocomplete组件?
通用Angular Material Autocomplete实现方案
核心思路
通过封装通用过滤逻辑、统一管理配置,甚至封装独立组件的方式,彻底避免为每个Autocomplete重复编写valueChanges订阅和过滤函数,大幅减少冗余代码。
实现步骤
1. 封装通用过滤函数
编写适配不同数据源的通用过滤函数,支持字符串数组和对象数组的匹配:
/** * 通用过滤函数 * @param value 输入框待匹配的值 * @param options 完整数据源数组 * @param displayField 对象数组中用于匹配的字段名(可选) */ filterOptions(value: string, options: any[], displayField?: string): any[] { const filterValue = value.toLowerCase().trim(); if (!filterValue) return [...options]; return options.filter(option => { const matchContent = displayField ? option[displayField].toLowerCase() : option.toLowerCase(); return matchContent.includes(filterValue); }); }
2. 统一管理Autocomplete配置
在组件内用配置对象集中管理所有Autocomplete的关键信息,批量初始化过滤流:
import { FormControl } from '@angular/forms'; import { Observable } from 'rxjs'; import { startWith, map } from 'rxjs/operators'; // 定义配置接口,规范每个Autocomplete的参数 interface AutoCompleteConfig { control: FormControl; options: any[]; displayField?: string; filteredOptions$: Observable<any[]>; } // 初始化所有Autocomplete的配置 autoCompleteConfigs: { [key: string]: AutoCompleteConfig } = { sizeType: { control: this.form.get('sizeTypeId') as FormControl, // 关联表单控件 options: this.sizeTypeList, // 你的尺寸单位数据源 displayField: 'name', filteredOptions$: new Observable() }, testOption: { control: this.myControl, // 独立FormControl options: this.testOptions, filteredOptions$: new Observable() } }; ngOnInit(): void { // 遍历配置,批量生成过滤流 Object.values(this.autoCompleteConfigs).forEach(config => { config.filteredOptions$ = config.control.valueChanges.pipe( startWith(''), map(value => this.filterOptions(value, config.options, config.displayField)) ); }); }
3. 模板复用写法
在HTML中直接调用配置好的数据流,统一模板结构:
表单组关联的Autocomplete示例
<mat-form-field class="col-4" appearance="fill"> <mat-label>{{ "SIZE_UNITS" | translate }}</mat-label> <input type="text" placeholder="SIZE_UNITS" id="select_size_type" matInput formControlName="sizeTypeId" [matAutocomplete]="sizeTypeAuto" /> <mat-autocomplete #sizeTypeAuto="matAutocomplete" (optionSelected)="handleOptionSelect($event, 'sizeType')" > <mat-option *ngFor="let item of autoCompleteConfigs.sizeType.filteredOptions$ | async" [value]="item.name" [id]="item.id + 'sizeUnits'" > {{ item.name }} </mat-option> </mat-autocomplete> </mat-form-field>
独立FormControl的Autocomplete示例
<mat-form-field class="col-3" appearance="fill"> <input type="text" placeholder="testing" matInput [formControl]="autoCompleteConfigs.testOption.control" [matAutocomplete]="testAuto" /> <mat-autocomplete #testAuto="matAutocomplete"> <mat-option *ngFor="let option of autoCompleteConfigs.testOption.filteredOptions$ | async" [value]="option" > {{ option }} </mat-option> </mat-autocomplete> </mat-form-field>
4. 通用选项选中处理
创建统一的选中事件处理函数,根据配置key区分不同逻辑:
handleOptionSelect(event: MatAutocompleteSelectedEvent, configKey: string): void { const selectedValue = event.option.value; switch(configKey) { case 'sizeType': // 原changeSizeType函数的逻辑 break; case 'testOption': // 其他Autocomplete的处理逻辑 break; } }
进阶优化:封装独立组件
如果多个页面需要使用Autocomplete,可封装成通用组件实现跨页面复用:
// generic-autocomplete.component.ts import { Component, Input, Output, EventEmitter } from '@angular/core'; import { FormControl } from '@angular/forms'; import { Observable } from 'rxjs'; import { startWith, map } from 'rxjs/operators'; @Component({ selector: 'app-generic-autocomplete', templateUrl: './generic-autocomplete.component.html', }) export class GenericAutocompleteComponent { @Input() control: FormControl; @Input() options: any[]; @Input() displayField?: string; @Input() label?: string; @Input() placeholder?: string; @Output() optionSelected = new EventEmitter<any>(); filteredOptions$: Observable<any[]>; ngOnInit(): void { this.filteredOptions$ = this.control.valueChanges.pipe( startWith(''), map(value => this._filter(value)) ); } private _filter(value: string): any[] { const filterValue = value.toLowerCase().trim(); if (!filterValue) return [...this.options]; return this.options.filter(option => { const matchContent = this.displayField ? option[this.displayField].toLowerCase() : option.toLowerCase(); return matchContent.includes(filterValue); }); } onOptionSelected(event: any): void { this.optionSelected.emit(event.option.value); } }
组件模板:
<!-- generic-autocomplete.component.html --> <mat-form-field appearance="fill"> <mat-label *ngIf="label">{{ label }}</mat-label> <input type="text" [placeholder]="placeholder" matInput [formControl]="control" [matAutocomplete]="auto" /> <mat-autocomplete #auto="matAutocomplete" (optionSelected)="onOptionSelected($event)"> <mat-option *ngFor="let option of filteredOptions$ | async" [value]="displayField ? option[displayField] : option" > {{ displayField ? option[displayField] : option }} </mat-option> </mat-autocomplete> </mat-form-field>
使用示例:
<app-generic-autocomplete [control]="form.get('sizeTypeId') as FormControl" [options]="sizeTypeList" [displayField]="'name'" [label]="'SIZE_UNITS' | translate" [placeholder]="'SIZE_UNITS' | translate" (optionSelected)="changeSizeType($event)" ></app-generic-autocomplete>
内容的提问来源于stack exchange,提问作者Sameh M Darwish
相关产品推荐
相关产品推荐

