Angular 5/Material 2 自动完成组件选中后显示值异常问题
Angular Material Autocomplete 显示名称同时存储ObjectId解决方案
我刚碰到过类似的头疼问题,你现在的核心矛盾就是既要让输入框友好显示固件名称,又要把对应的ObjectId传给后端存入MongoDB对吧?先理清楚你当前的困境:
- 设
[value]="firmware._id"时,选中选项后输入框直接显示一串ID,完全不符合UI预期; - 改成
[value]="firmware.name",显示倒是正常了,但后端拿不到需要的ObjectId,根本没法匹配MongoDB里的firmware字段定义(毕竟它要求存ObjectId类型)。
最终解决方案(结合vsoni和JEY的思路)
核心是利用Angular Material Autocomplete的displayWith属性控制显示内容,同时调整过滤逻辑适配输入字符串和选中对象两种场景,关键就是把过滤时的val转为字符串处理,完美解决冲突:
1. 调整组件TS代码
// hardwareCreate.component.ts myControl: FormControl = new FormControl(); availableFirmware = []; filteredFirmware: Observable<any[]>; selectedFirmware: any = null; // 用来存选中的完整固件对象,方便后续取ID ngOnInit() { this.terminalService.getFirmware().subscribe(firmware => { this.availableFirmware = firmware.firmware; }); this.filteredFirmware = this.myControl.valueChanges .pipe( startWith(''), map(val => this.filterFirmware(val)) ); } // 优化过滤函数,先把val转为字符串避免类型错误 filterFirmware(val: any): any[] { // 不管val是用户输入的字符串还是选中的固件对象,都统一转为字符串处理 const searchTerm = typeof val === 'string' ? val.toLowerCase() : val.name.toLowerCase(); return this.availableFirmware.filter(firmware => { return firmware.name.toLowerCase().includes(searchTerm); }); } // 定义输入框显示规则的函数 displayFirmware(firmware: any): string { return firmware ? firmware.name : ''; }
2. 修改HTML模板
<!-- hardwareCreate.component.html --> <div class="form-group"> <mat-form-field class="example-full-width"> <!-- 移除ngModel,避免和formControl冲突,统一用formControl绑定 --> <input type="text" placeholder="Firmware auswählen" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto1"> <!-- 绑定displayWith到我们定义的显示函数,控制输入框显示内容 --> <mat-autocomplete #auto1="matAutocomplete" [displayWith]="displayFirmware"> <!-- [value]绑定完整的固件对象,这样选中后能直接拿到ID --> <mat-option *ngFor="let firmware of filteredFirmware | async" [value]="firmware"> {{ firmware.name }} </mat-option> </mat-autocomplete> </mat-form-field> </div>
3. 获取ID用于数据库存储
当需要提交数据时,直接从表单控件里取对应的ObjectId即可:
// 提交时获取要存入MongoDB的ObjectId const firmwareId = this.myControl.value?._id; // 也可以监听控件值变化提前存好 // this.myControl.valueChanges.subscribe(val => { // this.selectedFirmware = val; // }); // 之后用this.selectedFirmware._id获取ID
为什么这样能解决问题?
displayWith是Angular Material专门用来分离“显示内容”和“实际绑定值”的属性,不管你[value]绑的是什么,输入框都会显示这个函数返回的内容;- 绑定完整固件对象到
[value],既能让输入框显示名称,又能拿到后端需要的ID; - 过滤时把
val转为字符串处理,解决了用户输入文本和选中对象两种场景下的过滤逻辑不一致问题,这也是你提到的“将val转换为字符串后问题解决”的核心关键点。
内容的提问来源于stack exchange,提问作者Sithys
相关产品推荐
相关产品推荐

