Angular级联下拉异常:新增文档组后子类别选择同步问题
Angular三级级联下拉同步选中问题修复
问题描述
在Angular中实现三级级联下拉功能:选择第一个下拉选项后,第二个下拉加载对应选项;选择第二个下拉选项后,第三个下拉加载对应选项。但存在异常:添加新的文档组后,在某一个文档组中选择子类别,其他文档组的子类别下拉会同步选中相同选项(例如选择Test One>Test 1,新文档组的子类别也会变成Test 1)。
问题根源
所有文档组共用了全局的subCategoryList和typeList数组。当任意一个文档组触发下拉选择时,会修改全局数组内容,而所有文档组的下拉选项都绑定这个全局数组,导致所有组的下拉选项同步变化。
解决方案
为每个文档组维护独立的子类别和类型列表,避免全局变量共享:
- 新增数组存储每个文档组的下拉状态,包含独立的
subCategoryList和typeList - 修改级联选择方法,根据当前文档组索引更新对应组的下拉列表
- 模板中绑定对应文档组的独立下拉列表,而非全局数组
修改后的TS代码
import 'zone.js/dist/zone'; import { Component } from '@angular/core'; import { CommonModule } from '@angular/common'; import { bootstrapApplication } from '@angular/platform-browser'; import { FormArray, FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule, } from '@angular/forms'; @Component({ selector: 'my-app', standalone: true, imports: [CommonModule, FormsModule, ReactiveFormsModule], templateUrl: 'main.html', }) export class App { categoryList: Array<any> = [ { name: "Test One", subCategoryList: [ { typeList: [''], name: "Test 1", }, { typeList: [''], name: "Test 1.1", }, { typeList: [''], name: "Test 2.2", }, ], }, { name: "Test Two", subCategoryList: [ { typeList: [''], name: "Test 2", }, { typeList: [''], name: "Test 2.1", }, { typeList: [''], name: "Test 2.2", }, ], }, { name: "Test Three", subCategoryList: [ { typeList: [''], name: "Test 3", }, ], }, ]; // 为每个文档组维护独立的下拉状态 documentDropdownStates: Array<{subCategoryList: any[], typeList: any[]}> = []; documentForm: FormGroup = this.fb.group({ appCode: ['123'], accountType: [''], emailId: ['test@aol.com'], IDV: [''], envelopeRequest: this.fb.group({ documents: this.fb.array([]), }), }); constructor(private fb: FormBuilder) {} ngOnInit() { this.initDocument(); } // 根据文档组索引更新子类别列表 changeCategoryList(comIndex: number, event: any) { const selectedCategory = event.target.value; const category = this.categoryList.find(cat => cat.name === selectedCategory); this.documentDropdownStates[comIndex].subCategoryList = category?.subCategoryList || []; // 切换类别时重置类型列表 this.documentDropdownStates[comIndex].typeList = []; // 重置当前组的子类别和类型表单值 this.documentFields(comIndex).at(comIndex * 2 + 1).get('value')?.setValue(''); } // 根据文档组索引更新类型列表 changeSubCategoryList(comIndex: number, event: any) { const selectedCategory = this.documentFields(comIndex).at(comIndex * 2).get('value')?.value; const selectedSubCategory = event.target.value; const category = this.categoryList.find(cat => cat.name === selectedCategory); const subCategory = category?.subCategoryList.find(sub => sub.name === selectedSubCategory); this.documentDropdownStates[comIndex].typeList = subCategory?.typeList || []; } initDocument() { this.documents.push(this.newDocument()); const documentIndex = this.documents.length - 1; this.newDocumentFieldGroup(documentIndex); // 初始化当前文档组的下拉状态 this.documentDropdownStates.push({ subCategoryList: [], typeList: [] }); } newDocument() { return this.fb.group({ name: new FormControl(''), documentId: new FormControl(''), documentFields: this.fb.array([]), }); } newDocumentFieldGroup(comIndex: number) { this.documentFields(comIndex).push(this.newDocumentFields()); this.documentFields(comIndex).push( this.newDocumentFields('documentSubCategory') ); } newDocumentFields(name = 'documentCategory') { return this.fb.group({ name: new FormControl(name), value: new FormControl( name == 'documentCategory' ? '--Choose Document Category--' : '' ), }); } get documents() { return (this.documentForm.controls.envelopeRequest as FormGroup).controls .documents as FormArray; } documentFields(comIndex: number) { return this.documents.controls[`${comIndex}`].get( 'documentFields' ) as FormArray; } documentFieldsIndexes(comIndex: number) { return Array(this.documentFields(comIndex).controls.length / 2) .fill(0) .map((x, i) => i * 2); } submit() { console.log(this.documentForm.value); } } bootstrapApplication(App);
修改后的HTML模板
<form [formGroup]="documentForm" (ngSubmit)="submit()"> <ng-container formGroupName="envelopeRequest"> <button type="button" (click)='initDocument()'>Add Document</button> <ng-container formArrayName="documents"> <ng-container *ngFor="let control of documents.controls; let comIndex=index" > <ng-container [formGroupName]="comIndex"> <div class="row justify-content-start mb-3"> <div class="col-md-1"> {{comIndex}} <input type="hidden" id="fname" name="fname" formControlName="documentId" /> <label for="formFile" class="col-form-label">File:</label> </div> <div class="col-md-6"> <input class="form-control" type="file" id="file" name="file" formControlName="name" /> </div> </div> <ng-container formArrayName="documentFields"> <ng-container *ngFor="let skillIndex of documentFieldsIndexes(comIndex);" > <div class="row mb-3"> <label class="col-sm-1 col-form-label">Category:</label> <div class="col-md-2"> <ng-container [formGroupName]="skillIndex"> <select class="form-select" formControlName="value" (change)="changeCategoryList(comIndex, $event)"> <option>Select</option> <option *ngFor="let c of categoryList"> {{c.name}} </option> </select> </ng-container> </div> <label class="col-auto col-form-label">Sub-Category:</label> <div class="col-md-2"> <ng-container [formGroupName]="skillIndex + 1"> <select class="form-select" formControlName="value" (change)="changeSubCategoryList(comIndex, $event)"> <option>Select</option> <option *ngFor="let s of documentDropdownStates[comIndex].subCategoryList">{{s.name}}</option> </select> </ng-container> </div> <label class="col-auto col-form-label">Type:</label> <div class="col-md-2"> <select class="form-select"> <option>Select</option> <option *ngFor="let t of documentDropdownStates[comIndex].typeList">{{t}}</option> </select> </div> </div> </ng-container> </ng-container> </ng-container> </ng-container> </ng-container> </ng-container> <button type="submit">Submit</button> </form> <pre>{{this.documentForm.value | json }}</pre>
内容的提问来源于stack exchange,提问作者fearless924
相关产品推荐
相关产品推荐

