如何在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
相关产品推荐
相关产品推荐

