Angular报Cannot read properties of undefined错误但数据正常显示如何解决
问题原因
- Angular 模板会在组件初始化时同步执行首次渲染,而你在
ngOnInit中发起的两个后端请求是异步操作,请求返回并给变量赋值的时机晚于首次渲染 - 首次渲染时:
product没有初始值为undefined,访问product.name触发报错;imagesProducts初始为空数组,imagesProducts[0]为undefined,访问.url触发报错 - 异步请求返回赋值后会触发 Angular 变更检测,重新渲染模板,此时变量都有有效值,所以页面可以正常显示内容,仅控制台留存首次渲染的报错信息
解决方案
下面是4种常用的解决方式,可根据场景选择:
方案1:使用可选链运算符(最简便)
直接修改模板代码,在可能为空的变量后加?.,当值为空时会直接返回undefined,不会抛出类型错误:
<div class="card img-big-wrap" style="text-align: center;"> <a href="#"><img [src]="imagesProducts[0]?.url" /></a> <h3 class="title">{{product?.name}}</h3> </div>
方案2:使用*ngIf控制渲染时机
在外层容器加*ngIf判断,等两个变量都拿到有效值之后再渲染对应DOM,从根源避免空值访问,还可以配合加loading状态提升体验:
<div *ngIf="product && imagesProducts.length > 0" class="card img-big-wrap" style="text-align: center;"> <a href="#"><img [src]="imagesProducts[0].url" /></a> <h3 class="title">{{product.name}}</h3> </div>
方案3:使用async管道(推荐)
将请求返回的Observable直接交给模板的async管道处理,不需要手动订阅,还能自动取消订阅避免内存泄漏:
TS代码修改:
import { Observable } from 'rxjs'; product$!: Observable<IResponseProduct>; imagesProducts$!: Observable<any[]>; ngOnInit(): void { let { id } = this._activatedRoute.snapshot.params; this.product$ = this._productSrv.getProduct(id); this.imagesProducts$ = this._productSrv.listImagenByIdProduct(id); }
模板代码修改:
<div class="card img-big-wrap" style="text-align: center;" *ngIf="{product: product$ | async, images: imagesProducts$ | async} as data"> <a href="#"><img [src]="data.images?.[0]?.url" /></a> <h3 class="title">{{data.product?.name}}</h3> </div>
方案4:给变量设置初始值
给两个变量设置符合类型结构的初始值,避免首次渲染时空值:
// 初始值结构要和IResponseProduct保持一致 product: IResponseProduct = { name: '' /* 其他属性也设置默认值 */ }; imagesProducts: any[] = [ { url: '' } ];
注:该方案仅适合结构简单的变量,灵活度低于前三个方案,不优先推荐
内容的提问来源于stack exchange,提问作者Frank Romero Morales
相关产品推荐
相关产品推荐

