I am trying to add a question in my form with a maximum of three selections. The question is "What is your favorite fruit?". To clarify, users should be able to select up to 3 fruits and no more. I can do this easily if the code is not in a reactive form. However, since I can't use ngModel
in a reactive form this has become a nightmare. Here is my code so far.
Ts file:
export class FruitSurveyComponent {
fruitForm: FormGroup;
availableFruits: string[] = ['Apple', 'Pear', 'Orange', 'Banana', 'Grapes', 'Pineapple'];
constructor(private formBuilder: FormBuilder) {
this.fruitForm = this.formBuilder.group({});
this.availableFruits.forEach(fruit => {
this.fruitForm.addControl(fruit, this.formBuilder.control(false));
});
}
canSelectFruit(fruit: string): boolean {
return this.fruitForm.value[fruit] || this.getSelectedFruitsCount() < 3;
}
getSelectedFruitsCount(): number {
const selectedFruits = this.availableFruits.filter(fruit => this.fruitForm.value[fruit]);
return selectedFruits.length;
}
onSubmit() {
const selectedFruits = this.availableFruits.filter(fruit => this.fruitForm.value[fruit]);
console.log('Selected Fruits:', selectedFruits);
}
}
HTML:
<div class="container">
<h1>Favorite Fruits Selector</h1>
<form [formGroup]="fruitForm" (ngSubmit)="onSubmit()">
<label>What are your favorite fruits? (Maximum of 3)</label>
<div *ngFor="let fruit of availableFruits">
<label>
<input type="checkbox" [formControlName]="fruit" [disabled]="!canSelectFruit(fruit)" />
{{ fruit }}
</label>
</div>
<button type="submit">Submit</button>
</form>
</div>
If you can work with NgModel
, you definitely able to work with Reactive Form.
For the implementation, you should have these 3 functionalities:
Checked/Unchecked the checkbox based on the form control value.
Disable the checkbox when the selected fruits are more than 3 and the fruit was not selected. And re-enable it when the previous conditions are not fulfilled.
A change event to add/remove the fruit from the form control value.
<input type="checkbox" [checked]="isFruitSelected(fruit)" [disabled]="!canSelectFruit(fruit)" (change)="onFruitChecked(fruit)" />
You should change the FormGroup structure with a fruits
control used to hold the fruits array instead of key-value pair.
this.fruitForm = this.formBuilder.group({
fruits: [[]],
});
canSelectFruit(fruit: string): boolean {
return this.isFruitSelected(fruit) || this.getSelectedFruitsCount() < 3;
}
getSelectedFruitsCount(): number {
return this.fruitForm.controls.fruits.value.length;
}
isFruitSelected(fruit: string) {
return this.fruitForm.controls.fruits.value.indexOf(fruit) > -1;
}
onFruitChecked(fruit: string) {
let selectedFruits: string[] = this.fruitForm.controls.fruits.value;
let selectedFruitIndex = selectedFruits.indexOf(fruit);
if (selectedFruitIndex > -1) selectedFruits.splice(selectedFruitIndex, 1);
else selectedFruits.push(fruit);
this.fruitForm.controls.fruits.setValue(selectedFruits);
}
onSubmit() {
const selectedFruits = this.fruitForm.controls.fruits.value;
console.log('Selected Fruits:', selectedFruits);
}