Angular Material自动补全搜索功能报错:TypeError无法读取undefined的'name'属性
解决Angular Material自动补全报错:TypeError: 无法读取undefined的'name'属性
我来帮你排查这个Angular Material自动补全的报错问题~首先咱们先拆解下报错的根源,再一步步修复:
问题根源分析
你遇到的TypeError: 无法读取undefined的'name'属性,主要来自两个地方:
- 过滤后的数组存在undefined元素:你的
filter函数里用filteredData[i] = this.persons[i]给数组赋值,当循环中某个person不满足过滤条件时,filteredData对应索引的位置就会是undefined。后续*ngFor遍历这个数组时,碰到undefined的项,访问person.name自然就报错了。 - 未处理初始状态下的空值:如果
persons是异步加载的,初始值为undefined,filter函数会直接返回undefined,导致filteredOptions流中出现空值,模板渲染时同样会触发报错。
分步修复方案
1. 修正过滤数组的赋值逻辑
放弃用索引赋值的方式,改用push()添加符合条件的元素,确保数组里不会出现undefined:
filter(val: string): any[] { const filteredData = []; // 如果persons还没加载,直接返回空数组 if (!this.persons) return []; const searchTerm = val.toLowerCase(); // 用for...of遍历更简洁直观 for (const person of this.persons) { // 简化条件判断,把空值/undefined的情况合并 if (this.basis.value === "name" || !this.basis.value) { if (person.name.toLowerCase().includes(searchTerm)) { filteredData.push(person); } } else if (this.basis.value === "id") { // 注意:如果id是数字类型,要先转成字符串再做小写匹配 if (person.id.toString().toLowerCase().includes(searchTerm)) { filteredData.push(person); } } } return filteredData; }
2. 给Observable添加初始值
在ngOnInit里,用startWith操作符给filteredOptions设置初始空数组,确保模板初始渲染时不会拿到undefined:
filteredOptions: Observable<any[]>; ngOnInit() { this.filteredOptions = this.name.valueChanges.pipe( map(val => this.filter(val)), // 初始时返回空数组,避免模板报错 startWith([]) ); }
3. 模板添加空值保护(双重保险)
在模板里访问person.name前,用可选链操作符?.做保护,就算数组里不小心出现undefined,也不会触发报错:
<input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="name" [matAutocomplete]="auto"> <mat-autocomplete #auto="matAutocomplete"> <!-- 去掉多余的*ngIf="filteredOptions",startWith已经确保有初始值 --> <mat-option *ngFor="let person of filteredOptions | async" [value]="person?.name"> {{person?.name}} </mat-option> </mat-autocomplete>
4. 额外优化建议
- 给
persons定义类型并初始化为空数组,比如:persons: Person[] = [];,从根源避免undefined的情况 - 可以用数组的
filter方法简化过滤逻辑,代码更简洁易读:
// 假设你有Person类型定义:interface Person { name: string; id: string | number; } filter(val: string): Person[] { if (!this.persons || !val) return this.persons; const searchTerm = val.toLowerCase(); return this.persons.filter(person => { if (this.basis.value === "name" || !this.basis.value) { return person.name.toLowerCase().includes(searchTerm); } else if (this.basis.value === "id") { return person.id.toString().toLowerCase().includes(searchTerm); } return false; }); }
内容的提问来源于stack exchange,提问作者Nidhi
相关产品推荐
相关产品推荐

