Angular Material Autocomplete选择复杂对象后如何正确显示属性?
解决Angular Material Autocomplete选中对象后输入框显示
[object Object]的问题 核心问题分析
你的FormControl定义为FormControl<string>,但mat-option绑定的是TokenNameWithId对象,选中后输入框会将对象直接转为字符串,导致显示[object Object]。同时原有过滤逻辑未兼容对象类型的输入值,会引发后续逻辑错误。
解决方案步骤
1. 调整FormControl类型
将tokenNamesControl的类型改为支持用户输入的字符串和选中的对象两种情况:
public tokenNamesControl = new FormControl<TokenNameWithId | string>('', { nonNullable: true, });
2. 添加displayWith函数
在组件中定义函数,指定输入框需要显示的文本内容:
displayTokenName(token?: TokenNameWithId | string): string { // 区分处理用户输入的字符串和选中的对象 return typeof token === 'string' ? token : token?.displayName || ''; }
3. 修正过滤逻辑
更新ngOnInit中的过滤逻辑,兼容字符串和对象类型的输入值:
ngOnInit(): void { this.filteredTokenNames = combineLatest([ this.tokenNamesControl.valueChanges.pipe(startWith('')), this.tokenNames$, ]).pipe( debounceTime(250), map(([value, tokenNamesWithId]) => { // 将输入值统一转为过滤用的字符串 const filterValue = typeof value === 'string' ? value.toLowerCase() : value.displayName.toLowerCase(); return filterValue ? this._filter(filterValue, tokenNamesWithId) : tokenNamesWithId; }) ); }
保持_filter函数不变(此时传入的value已确保是字符串):
private _filter(value: string, tokenNamesWithId: TokenNameWithId[]): TokenNameWithId[] { return tokenNamesWithId.filter(token => token.displayName.toLowerCase().includes(value) ); }
4. 配置模板中的displayWith属性
在mat-autocomplete上绑定刚定义的displayWith函数:
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayTokenName"> @for (tokenName of filteredTokenNames | async ; track tokenName) { <mat-option [value]="tokenName">{{tokenName.displayName}}</mat-option> } </mat-autocomplete>
修改后的完整组件代码
import { Component, OnInit } from '@angular/core'; import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; import {AsyncPipe} from '@angular/common'; import {MatAutocompleteModule} from '@angular/material/autocomplete'; import {MatInputModule} from '@angular/material/input'; import {MatFormFieldModule} from '@angular/material/form-field'; import { TokenNameWithId } from '../../../shared/models/card.model'; import { Observable, combineLatest, debounceTime, map, startWith } from 'rxjs'; import { Store } from '@ngrx/store'; import { selectAllTokenNames } from '../+state/token-names.selectors'; @Component({ selector: 'tokenator-tokens-dropdown', standalone: true, imports: [FormsModule, MatFormFieldModule, MatInputModule, MatAutocompleteModule, ReactiveFormsModule, AsyncPipe ], templateUrl: './tokens-dropdown.component.html', styleUrl: './tokens-dropdown.component.scss', }) export class TokensDropdownComponent implements OnInit { public tokenNamesControl = new FormControl<TokenNameWithId | string>('', { nonNullable: true, }); public filteredTokenNames!: Observable<TokenNameWithId[]>; private tokenNames$ = this.store.select(selectAllTokenNames); constructor(private store: Store) { } ngOnInit(): void { this.filteredTokenNames = combineLatest([ this.tokenNamesControl.valueChanges.pipe(startWith('')), this.tokenNames$, ]).pipe( debounceTime(250), map(([value, tokenNamesWithId]) => { const filterValue = typeof value === 'string' ? value.toLowerCase() : value.displayName.toLowerCase(); return filterValue ? this._filter(filterValue, tokenNamesWithId) : tokenNamesWithId; }) ); } displayTokenName(token?: TokenNameWithId | string): string { return typeof token === 'string' ? token : token?.displayName || ''; } private _filter(value: string, tokenNamesWithId: TokenNameWithId[]): TokenNameWithId[] { return tokenNamesWithId.filter(token => token.displayName.toLowerCase().includes(value) ); } }
组件选择说明
mat-autocomplete搭配matInput是Angular Material中实现复杂对象选择+自动完成的标准方案,完全匹配你的需求,无需更换其他组件。
内容的提问来源于stack exchange,提问作者Ross Graeber
相关产品推荐
相关产品推荐

