Angular Material多选下拉框搜索功能实现及已选值丢失解决
问题核心原因
- 搜索逻辑直接用过滤结果覆盖渲染
mat-option的可选项数组,当已选中的选项不匹配当前搜索关键词时,对应的mat-option会从DOM移除。Angular Material多选组件的选中值展示,依赖已渲染的mat-option节点提取显示文本,没有对应节点时哪怕formControl里保留了选中值,也无法在触发器位置展示,给人“选中项消失”的错觉。 - 现有代码存在语法错误(
toLowerCase()后多余的点)、模板引用变量和TS取值不匹配的问题,会进一步干扰正常运行逻辑。
TS层调整
- 拆分两个独立数组:
_provider存储从接口加载的全量提供商数据,仅做读取不修改;provider存储当前渲染用的过滤后列表,承担mat-option的数据源。 - 重写搜索过滤逻辑:过滤结果合并两部分内容——① 匹配当前输入关键词的选项;② 所有已被选中的选项(即使不匹配搜索关键词),去重后赋值给渲染列表,保证已选中的选项始终存在对应的
mat-option节点。 - 通过
@ViewChild绑定模板上的搜索输入框变量,修正原有语法错误。
调整后的TS参考代码:
// 类成员定义 provider: any[] = []; _provider: any[] = []; // 全量数据,接口加载完成后赋值,不做覆盖修改 providers = new FormControl<string[]>([]); // 绑定模板上的#multiUserSearch输入框 @ViewChild('multiUserSearch') multiUserSearchInput!: ElementRef<HTMLInputElement>; onInputChange() { const searchInput = this.multiUserSearchInput.nativeElement.value?.toLowerCase().trim() || ''; const selectedValues = this.providers.value || []; // 匹配搜索关键词的选项 const matchedByKeyword = this._provider.filter(item => item.PROV.toLowerCase().includes(searchInput) ); // 已选中但不在当前搜索结果里的选项,单独保留 const selectedOutOfKeyword = this._provider.filter(item => selectedValues.includes(item.PROV) && !item.PROV.toLowerCase().includes(searchInput) ); // 合并两类结果,无重复 this.provider = [...matchedByKeyword, ...selectedOutOfKeyword]; }
模板层调整
- 优化
mat-select-trigger的展示逻辑,直接输出表单值数组会显示为原始数组格式,拼接为逗号分隔的字符串提升可读性。 - 保持组件结构符合Angular Material的交互规范,避免输入框的默认事件影响下拉框收起逻辑。
调整后的HTML参考代码:
<mat-form-field appearance="fill"> <mat-label>Providers</mat-label> <mat-select multiple [formControl]="providers"> <mat-select-trigger> {{ providers.value?.join(', ') || '' }} </mat-select-trigger> <input type="text" autocomplete="off" matInput placeholder="Search By Provider" #multiUserSearch (input)="onInputChange()"> <mat-option *ngFor="let item of provider" [value]="item.PROV"> {{ item.PROV }} </mat-option> </mat-select> </mat-form-field>
补充优化建议
- 初始化加载完全量
_provider后,直接将全量数据赋值给provider作为初始渲染值,避免初始状态下拉框为空。 - 针对数据量较大的场景,给输入监听增加防抖逻辑,减少高频过滤计算带来的性能损耗。
- 可在搜索输入框上增加点击冒泡阻断逻辑,避免用户点击输入框时误触发下拉框收起。
内容的提问来源于stack exchange,提问作者Sharvani
相关产品推荐
相关产品推荐

