Angular *ngFor遍历对象数组访问嵌套属性无渲染结果问题
问题根源
访问不到对应字段的核心原因是数据结构层级判断错误:
- 你用
*ngFor遍历filterPeriodos()返回的数组时,循环项实际是最外层的运输方式对象,你把它命名为periodo本身就存在认知误导; - 这个运输方式对象下的
periodos字段是数组类型,不是单个对象,你直接写periodo.periodos.periodo相当于从数组上读取periodo属性,拿到的永远是undefined,自然渲染不出内容。
从接口返回的结构可以明确层级关系:
// *ngFor直接遍历到的外层对象(你代码里命名为periodo的变量) { "id": 1, "nome": "Retirada na Loja", "tipo": "RETIRA", "periodos": [ // 这个字段是数组,不是单个对象 // 数组内的元素才是你要访问的、带id/periodo字段的时段对象 {"id":8, "periodo":"Comercial (das 8h às 19h)", "corte":"16:00"}, {"id":16, "periodo":"Domingos ou Feriado (Das 9h as 14h)", "corte":"12:00"} ] }
另外你当前写法存在性能隐患:模板中直接调用filterPeriodos()方法,Angular每次变更检测都会重新执行这个方法,会产生无意义的性能消耗。
修复方案
场景1:需要展示每个运输方式下的所有时段
因为periodos是数组,需要嵌套一层*ngFor遍历子数组,才能拿到内部的时段字段,修改后的模板代码如下:
<div class="form-check" *ngFor="let transporte of filterPeriodos()"> <!-- 遍历当前运输方式下的所有时段 --> <ng-container *ngFor="let periodoOpt of transporte.periodos"> <input class="form-check-input mr-2" type="radio" [id]="'periodo' + periodoOpt.id" [value]="periodoOpt.id" formControlName="periodo" (change)="changePeriodo(periodoOpt, transporte)" > <label class="form-check-label" [for]="'periodo' + periodoOpt.id"> {{ periodoOpt.periodo }} <span class="text-danger">{{ formGeral.value.vFrete | currency: 'BRL' }}</span> </label> </ng-container> </div>
注意:把原来插值写id、value的方式改成属性绑定
[id]、[value]是Angular推荐写法,能避免插值渲染完成前的属性值异常问题。
场景2:每个运输方式只需要展示第一个/指定时段
如果不需要展示所有时段,不需要嵌套循环,直接通过数组下标取值即可,记得用安全导航运算符?.避免空数组报错:
<div class="form-check" *ngFor="let transporte of filterPeriodos()"> <input class="form-check-input mr-2" type="radio" [id]="'periodo' + transporte.periodos[0]?.id" [value]="transporte.periodos[0]?.id" formControlName="periodo" (change)="changePeriodo(transporte.periodos[0])" > <label class="form-check-label" [for]="'periodo' + transporte.periodos[0]?.id"> {{ transporte.periodos[0]?.periodo }} <span class="text-danger">{{ formGeral.value.vFrete | currency: 'BRL' }}</span> </label> </div>
性能优化(强烈建议)
不要在模板里直接调用过滤方法,改成在依赖数据变化时把过滤结果存到组件属性中,模板直接遍历属性即可,避免重复执行过滤逻辑:
- 组件类中新增存储过滤结果的属性:
filteredTransporteList: any[] = [];
- 把过滤逻辑抽成独立方法,在组件初始化、表单值变化时调用,给上述属性赋值:
ngOnInit() { this.updateFilteredPeriodos(); // 监听表单变化自动重新过滤 this.formGeral.valueChanges.subscribe(() => { this.updateFilteredPeriodos(); }) } updateFilteredPeriodos() { const object = this.formGeral.value.data; const jsDate = new Date(object.singleDate?.jsDate); jsDate.setUTCHours(23,59,59,999); this.dataFormat = jsDate; if (this.storeS.layout.emp.id === 1 && this.formGeral.value.entregaBool) { this.filteredTransporteList = this.transporte.filter( transp => transp.tipo === "RETIRA" ); return; } this.filteredTransporteList = this.transporte; }
- 模板中直接遍历过滤后的属性即可:
<div class="form-check" *ngFor="let transporte of filteredTransporteList"> <!-- 内部时段遍历逻辑和上述场景一致 --> </div>
内容的提问来源于stack exchange,提问作者Leonardo
相关产品推荐
相关产品推荐

