You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular *ngFor遍历对象数组访问嵌套属性无渲染结果问题

问题根源

访问不到对应字段的核心原因是数据结构层级判断错误:

  1. 你用*ngFor遍历filterPeriodos()返回的数组时,循环项实际是最外层的运输方式对象,你把它命名为periodo本身就存在认知误导;
  2. 这个运输方式对象下的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>

性能优化(强烈建议)

不要在模板里直接调用过滤方法,改成在依赖数据变化时把过滤结果存到组件属性中,模板直接遍历属性即可,避免重复执行过滤逻辑:

  1. 组件类中新增存储过滤结果的属性:
filteredTransporteList: any[] = [];
  1. 把过滤逻辑抽成独立方法,在组件初始化、表单值变化时调用,给上述属性赋值:
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;
}
  1. 模板中直接遍历过滤后的属性即可:
<div class="form-check" *ngFor="let transporte of filteredTransporteList">
  <!-- 内部时段遍历逻辑和上述场景一致 -->
</div>

内容的提问来源于stack exchange,提问作者Leonardo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 16:15:45