Reputation: 83
So I came with issue related to angular dropdowns, I have multiple dropdowns where they are dependent on last dropdowns response. In simple word suppose I have Class - Subject - Part like these tree structure. when I select the Class then the all Subjects inside the Class will appear. but here when there is only on Subject is there in Class then it is get automatically selected and I cant even interact with that option and the next dropdown is depends on these Subject dropdowns value. How to tackle these issue in angular??
<form [formGroup]="addPartsForm" (ngSubmit)="addPart()">
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="control">
<label for="board_id">Select Board</label>
<select name="board_id" id="board_id" formControlName="board_id" class="form-control" (change)="onBoardSelectionChange($event, addPartsForm)">
<option [ngValue]="null" disabled selected>Select board</option>
<option *ngFor="let board of boardsAllData" [value]="board.id">{{board.name}}</option>
</select>
<div class="errorMsg" *ngIf="addPartsForm.get('board_id')?.touched && addPartsForm.get('board_id')?.invalid">
<p class="error">Please select a board</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="control">
<label for="class_id">Select Class</label>
<select name="class_id" id="class_id" formControlName="class_id" class="form-control" (change)="onClassSelectionChange($event, addPartsForm)">
<option [ngValue]="null" >Select class</option>
<option *ngFor="let class of classAllData" [value]="class.id">{{class.name}}</option>
</select>
<div class="errorMsg" *ngIf="addPartsForm.get('class_id')?.touched && addPartsForm.get('class_id')?.invalid">
<p class="error">Please select a class</p>
</div>
</div>
</div>
<div class="col-md-6 mt-2">
<div class="control">
<label for="subject_id">Select Subject</label>
<select name="subject_id" id="subject_id" formControlName="subject_id" class="form-control">
<option [ngValue]="null" >Select subject</option>
<option *ngFor="let subject of subjectAllData" [value]="subject.id">{{subject.name}}</option>
</select>
<div class="errorMsg" *ngIf="addPartsForm.get('subject_id')?.touched && addPartsForm.get('subject_id')?.invalid">
<p class="error">Please select a subject</p>
</div>
</div>
</div>
<div class="col-md-6 mt-2">
<div class="control">
<label for="partsName">Enter Part Name</label>
<input type="text" name="partsName" id="partsName" formControlName="part_name" class="form-control" placeholder="Enter part name">
</div>
</div>
<div class="col-md-6 mt-3">
<div class="control">
<label for="description">Enter Part Description</label>
<input type="text" name="description" id="description" formControlName="description" class="form-control" placeholder="Enter part description">
</div>
</div>
</div>
</div>
<div class="card-footer">
<button class="button" mat-flat-button type="button" (click)="addPartsForm.reset()">Clear</button>
<button class="button" mat-flat-button [disabled]="!addPartsForm.valid">Add Part</button>
</div>
</form>
Upvotes: 1
Views: 25
Reputation: 115
I had a scenario in Angular with multiple dependent dropdowns:
app.component.html
<form [formGroup]="addPartsForm" (ngSubmit)="addPart()">
<div class="card-body">
<div class="row">
<div class="col-md-6">
<label>Select Board</label>
<select formControlName="board_id" class="form-control" (change)="onBoardSelectionChange($event)">
<option [ngValue]="null" disabled selected>Select board</option>
<option *ngFor="let board of boardsAllData" [value]="board.id">{{ board.name }}</option>
</select>
</div>
<div class="col-md-6">
<label>Select Class</label>
<select formControlName="class_id" class="form-control" (change)="onClassSelectionChange($event)">
<option [ngValue]="null">Select class</option>
<option *ngFor="let class of classAllData" [value]="class.id">{{ class.name }}</option>
</select>
</div>
<div class="col-md-6 mt-2">
<label>Select Subject</label>
<select formControlName="subject_id" class="form-control" (change)="onSubjectSelectionChange($event)">
<option [ngValue]="null">Select subject</option>
<option *ngFor="let subject of subjectAllData" [value]="subject.id">{{ subject.name }}</option>
</select>
</div>
<div class="col-md-6 mt-2">
<label>Enter Part Name</label>
<input type="text" formControlName="part_name" class="form-control" placeholder="Enter part name" />
</div>
<div class="col-md-6 mt-3">
<label>Enter Part Description</label>
<input type="text" formControlName="description" class="form-control" placeholder="Enter part description" />
</div>
</div>
</div>
<div class="card-footer">
<button type="button" class="btn btn-secondary" (click)="addPartsForm.reset()">Clear</button>
<button class="btn btn-primary" type="submit" [disabled]="!addPartsForm.valid">Add Part</button>
</div>
</form>
app.component.ts
addPartsForm!: FormGroup;
boardsAllData: any[] = [];
classAllData: any[] = [];
subjectAllData: any[] = [];
partsAllData: any[] = [];
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.initializeForm();
this.loadBoards();
}
initializeForm() {
this.addPartsForm = this.fb.group({
board_id: [null, Validators.required],
class_id: [null, Validators.required],
subject_id: [null, Validators.required],
part_name: ['', Validators.required],
description: [''],
});
}
loadBoards() {
this.boardsAllData = [
{ id: 'b1', name: 'CBSE' },
{ id: 'b2', name: 'ICSE' },
];
}
onBoardSelectionChange(event: any) {
const boardId = event.target.value;
if (boardId) {
const classAllData = [
{ id: 'c1', name: 'Class 10', board_id: 'b1' },
{ id: 'c2', name: 'Class 12', board_id: 'b2' },
];
this.classAllData = classAllData.filter((x) => x.board_id == boardId);
this.addPartsForm.patchValue({ class_id: null, subject_id: null });
this.subjectAllData = [];
this.partsAllData = [];
if (this.classAllData.length === 1) {
// If only one subject, select it but still keep the dropdown enabled
this.addPartsForm.get('class_id')?.setValue(this.classAllData[0].id);
this.onClassSelectionChange({
target: { value: this.classAllData[0].id },
});
} else {
// Reset if multiple subjects
this.addPartsForm.get('class_id')?.setValue(null);
}
}
}
onClassSelectionChange(event: any) {
const classId = event.target.value;
if (classId) {
const subjectAllData = [
{ id: 's1', name: 'Mathematics', class_id: 'c1' },
{ id: 's2', name: 'Science', class_id: 'c1' },
{ id: 's3', name: 'Physics', class_id: 'c2' },
];
const data = subjectAllData.filter((x) => x.class_id == classId);
this.subjectAllData = data;
if (data.length === 1) {
this.addPartsForm.patchValue({ subject_id: data[0].id });
this.addPartsForm.updateValueAndValidity();
this.loadParts(data[0].id);
} else {
this.addPartsForm.patchValue({ subject_id: null });
this.partsAllData = [];
}
}
}
onSubjectSelectionChange(event: any) {
const subjectId = event.target.value;
if (subjectId) this.loadParts(subjectId);
}
loadParts(subjectId: string) {
this.partsAllData = [
{ id: 'p1', name: 'Algebra', subject_id: 's1' },
{ id: 'p2', name: 'Geometry', subject_id: 's1' },
{ id: 'p3', name: 'Thermodynamics', subject_id: 's3' },
];
}
addPart() {
if (this.addPartsForm.valid) {
}
}
Sample mock json
{
"boardsAllData": [
{ "id": "b1", "name": "CBSE" },
{ "id": "b2", "name": "ICSE" }
],
"classAllData": [
{ "id": "c1", "name": "Class 10", "board_id": "b1" },
{ "id": "c2", "name": "Class 12", "board_id": "b1" },
{ "id": "c3", "name": "Class 10", "board_id": "b2" }
],
"subjectAllData": [
{ "id": "s1", "name": "Mathematics", "class_id": "c1" },
{ "id": "s2", "name": "Science", "class_id": "c1" },
{ "id": "s3", "name": "Physics", "class_id": "c2" }
],
"partsAllData": [
{ "id": "p1", "name": "Algebra", "subject_id": "s1" },
{ "id": "p2", "name": "Geometry", "subject_id": "s1" },
{ "id": "p3", "name": "Thermodynamics", "subject_id": "s3" }
]
}
Upvotes: 0