About your stackblitz, I forked your stackblitz
The problem is that your function onCheckArray don't change the FormArray (yes, you changed the value, but not the FormArray, so there was any validation. See your function edited
//I repite the getter stage, so the answer can be understood
get stage(): FormArray {
return this.Form.get('stage') as FormArray;
}
onCheckArray(event) { //you needn't send the value
/* Selected */
if (event.target.checked) {
// Add a new control in the arrayForm,
// use push, but add a new FormControl TO the formArray
this.stage.push(new FormControl(event.target.value));
} else {
/* unselected */
// find the unselected element
let i: number = 0;
//we iterate over the formArray
for (i = 0; i < this.stage.value.length; i++) {
if (this.stage.value[i] == event.target.value) {
//use removeAt(i)
this.stage.removeAt(i);
return;
}
}
}
}
Well, your function validators can be more easy, just check the length of the array
minSelectedCheckboxes(min = 1) {
return (formArray: FormArray) => {
return formArray.controls.length >= min ? null : { required: true };
};
}
And there are a problem if you initialize the FormArray
this.Form = this.fb.group({
stage: this.fb.array([new FormControl("3")], this.minSelectedCheckboxes())
})
Your .html must be like
<div class="form-check-label">
<label class="checkbox-inline">
<input type="checkbox" class="checkbox" name="none" value="1" #noneChk
<!--see how indicate when is checked-->
[checked]="stage.value.indexOf('1')>=0"
(change)="onCheckArray($event)">
1
</label>
</div>
Well, I you are asking about a more simple way to manage an array of checkboxes, we can take another aproach. Our FormArray will be an array of controls with value true/false, and we has a function taht transform this array in our values.
options=["1","2","3","4"]; //our options
get valuesSelected() ; //a function that return the options selected
{
return this.options.filter((x,index)=>this.newForm.get('stage').value[index])
}
//see how create the formArray, always has the same number of
//elements that our options
this.newForm=new FormGroup({
stage:new FormArray(this.options
.map(x=>new FormControl(false)),this.minTrueCheckboxes())
})
minTrueCheckboxes(min = 1) {
return (formArray: FormArray) => {
return formArray.value.filter(x=>x).length>=min? null : { required: true };
};
}
And our .html becomes like
<form class="form" [formGroup]="newForm" (ngSubmit)="onSubmit()">
<div formArrayName="stage">
<label class="checkbox-inline" *ngFor="let control of newForm.get('stage').controls;let i=index">
<input type="checkbox" class="checkbox" [formControl]="control" >
{{options[i]}}
</label>
</div>
</form>
<p>{{ valuesSelected | json }}</p>