get multiple checkbox value as an array in angular
i'm trying to get values from multiple checkbox here https://stackblitz.com/edit/angular-ivy-uahtjx i try this approach but didn't with for me https://stackblitz.com/edit/quiz-answer-value i think it's because the JSON schema is different, first one is array, and the second one is object.
i set up my html like this
<div *ngFor="let option of form.options">
<label><input (change)="onChange(i,j, form.code,check.checked)" #check
[value]="answers[i].value.forms[j].answer.toString().indexOf(form.code)>=0" formControlName="answer" type="checkbox">{{option}}</label>
</div>
and for my change function like this
onChange(indexi: number, indexj: number, code: string, isChecked: boolean) {
const control = this.answerArray.at(indexi).get("forms")['controls'][indexj].get('answer');
console.log(control);
}
can someone help me?
Thre're several errors in your code.
The last stackblitz you indicate (that gone from this SO) is an "imaginative" way to mannage a series of check-boxes to feed a formControl that store an array of strings. The idea is that the input has [checked]
and (change)
, but NOT formControlName (it's the reason because at first the check-boxes became "checked"). The formControl has no input in the form. Yes, the formControl exist, but has no input.
The [checked]
of the check-box is a function that indicate if the "option" is include in the value of the control (using indexOf)
The (change)
has as arguments, the indexes -to localize the formControl-, the value of the "option" and if is checked or not.
A more simple stackblitz to show this concept:
<!--see that "answer" has no input, it's only a variable in .ts-->
<div *ngFor="let option of options">
<input #check type="checkbox"
[checked]="answer.indexOf(option)>=0"
(change)="onChange(option,check.checked)"
>
{{option}}
</div>
answer=["check 2"]
options=["check 1","check 2","check3"]
onChange(option:string,checked:boolean)
{
if (checked && this.answer.indexOf(option)<0)
this.answer=[...this.answer,option]
.sort((a,b)=>this.options.indexOf(a)>this.options.indexOf(b)?1:-1)
if (!checked)
this.answer=this.answer.filter(x=>x!=option)
}
Well, in your code
1.-Change the form (please, see the comments in the code)
<div *ngIf="form.type == 'checkbox'">
<p>{{form.title}}</p>
<div *ngFor="let option of form.options">
<!--in your code WRONG (change)="onChange(i,j, form.code,check.checked)" -->
<!-- see that we need send the "option", not the form.code-->
<label><input #check (change)="onChange(i,j, option,check.checked)"
<!--use checked, not value, and remove the "toString"-->
[checked]="answers[i].value.forms[j].answer.indexOf(option)>=0"
<!--see that we has no formControlName="answer" -->
type="checkbox">{{option}}</label>
</div>
</div>
The function onChange, it's simply if checked=true add the "code" and if checked=false remove the "code". Well, there are a dificult that is "sort" the responses. For sort the response, we compare the indexOf the value in the "options"
I use an auxiliar variable "options" to get the "options"
2.-Change your function onChange by
onChange(indexi: number, indexj: number, code: string, isChecked: boolean) {
const control = this.answerArray.at(indexi).get("forms")["controls"][indexj]
.controls.answer;
const options=this.listFormField[indexi].sectionItems[indexj].options
//options will be, eg. ["check 1","check 2","check 3"]
if (isChecked && control.value.indexOf(code) < 0)
control.setValue(
[...control.value, code].sort((a: string, b: string) =>
options.indexOf(a) >options.indexOf(b)
? 1
: -1
)
);
if (!isChecked && control.value.indexOf(code) >= 0)
control.setValue(control.value.filter(x => x != code));
}
NOTE: You need revised the code, Actually, when you create the form, all yours "answers" are arrays (only need to be array the "answer" that they are ansers of a check-boxs)
Updated To avoid errors if answer is null, we can or avoid when create the form or, another option, change the code in checked as
[checked]="(answers[i].value.forms[j].answer || []).indexOf(option)>=0"
To path value we can, if only is an element, e.g.
const i=0
const j=1
this.response.get('answers.'+i+'.forms.'+j+'.answer')
.patchValue(["check 1","check 2"])
Yes, to get an "answer" we can use "get" using the index. Perhafs this makes understand because when we use a formArray of formGroup, we write [formGroupName]="i"
. If we want to make a pathValue over a FormGroup, we need take account, that if we make pathValue over an array, pathValue NOT add elements to the formArray, so if we send more elements, this it's not added. futhermore, if we send less elements, pathValue, remove the elements
take account this, we can also make,e.g.
this.response.get('answers.'+i+'.forms')
.patchValue(
[
{answer:"radio 2"},
{answer:["check 1","check 2"]},
{answer:"text input"},
{answer:"text area"},
{answer:["check 6"]},
]
)