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

如何在Angular模板中按类型分组展示动态嵌套复选框列表

按类型分组展示Angular复选框(结合FormArray)

问题分析

你当前的实现是将所有复选框平铺展示,因为直接遍历了整个FormArray,没有结合类型信息做分组。要实现按类型分组,核心是先将allCodes与types关联分组,再在模板中按分组渲染,同时保持与FormArray控件的正确绑定。


解决方案步骤

1. 构建分组后的数据源

首先在组件中处理API返回的types和allCodes,生成每个类型对应的代码列表(包括无代码的类型):

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, FormControl } from '@angular/forms';

@Component({
  selector: 'app-codes',
  templateUrl: './codes.component.html',
  styleUrls: ['./codes.component.css']
})
export class CodesComponent implements OnInit {
  types: { typeName: string, id: number }[] = [];
  allCodes: { codeName: string, id: number, codeTypeId: number }[] = [];
  checkedCodes: { id: number }[] = []; // 假设这是已选中的代码列表
  codesForm!: FormGroup;
  groupedCodes!: { typeName: string, id: number, codes: typeof this.allCodes }[];

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    // 模拟API获取数据(实际项目中替换为HTTP请求)
    this.types = [
      { typeName: "Type 1", id: 1 },
      { typeName: "Type 2", id: 2 },
      { typeName: "Type 3", id: 3 },
      { typeName: "Type 4", id: 4 },
      { typeName: "Type 5", id: 5 },
      { typeName: "Type 6", id: 6 }
    ];
    this.allCodes = [
      { codeName: "code1", id: 1, codeTypeId: 1 },
      { codeName: "code2", id: 2, codeTypeId: 5 },
      { codeName: "code3", id: 3, codeTypeId: 2 },
      { codeName: "code4", id: 4, codeTypeId: 3 },
      { codeName: "code5", id: 5, codeTypeId: 4 },
      { codeName: "code6", id: 6, codeTypeId: 4 },
      { codeName: "code7", id: 7, codeTypeId: 3 } // 修正原数据id重复问题
    ];

    // 构建分组数据:每个类型对应其下的代码列表
    this.groupedCodes = this.types.map(type => ({
      ...type,
      codes: this.allCodes.filter(code => code.codeTypeId === type.id)
    }));

    this.codesForm = this.createFormGroup();
    this.addCheckboxes();
  }

  createFormGroup() {
    return this.fb.group({
      codes: new FormArray([])
    });
  }

  private addCheckboxes() {
    this.allCodes.forEach((o) => {
      const isChecked = this.checkedCodes.some(el => el.id === o.id);
      (this.codesForm.controls['codes'] as FormArray).push(new FormControl(isChecked));
    });
  }

  // 获取代码在allCodes中的索引,用于关联FormArray控件
  getCodeIndex(code: { id: number }): number {
    return this.allCodes.findIndex(item => item.id === code.id);
  }

  onSubmit() {
    // 提交逻辑:获取选中的代码
    const selectedCodes = this.allCodes.filter((_, index) => {
      return (this.codesForm.get('codes') as FormArray).controls[index].value;
    });
    console.log('Selected codes:', selectedCodes);
  }
}

2. 模板中按分组渲染复选框

修改模板,遍历分组数据,每个类型下渲染对应的复选框(或无代码提示):

<form [formGroup]="codesForm" (ngSubmit)="onSubmit()">
  <div *ngFor="let group of groupedCodes" class="mb-3">
    <h3>{{ group.typeName }}</h3>
    <!-- 无代码时显示提示 -->
    <div *ngIf="group.codes.length === 0" class="text-muted">-- No code added --</div>
    <!-- 遍历当前类型下的所有代码 -->
    <div 
      class="custom-control custom-checkbox mb-1" 
      *ngFor="let code of group.codes"
    >
      <ng-container *ngIf="getCodeIndex(code) as controlIndex">
        <input 
          type="checkbox" 
          class="custom-control-input" 
          id="code-{{ code.id }}" 
          [formControl]="(codesForm.get('codes') as FormArray).controls[controlIndex]"
        >
        <label class="custom-control-label" for="code-{{ code.id }}">{{ code.codeName }}</label>
      </ng-container>
    </div>
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>

关键说明

  • 分组逻辑:通过types.map结合allCodes.filter,将每个类型与对应的代码关联,确保所有类型(包括无代码的)都能展示。
  • FormArray绑定:保持FormArray为扁平结构(每个代码对应一个FormControl),通过getCodeIndex方法找到代码在原数组中的索引,从而关联到正确的表单控件。
  • 无代码提示:通过*ngIf="group.codes.length === 0"判断并显示提示文本。

这种方式既满足了分组展示的需求,又保持了表单数据结构的简洁性,便于后续提交处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 06:49:05