i\'m creating quiz app using angular and i have code like this
ngOnInit() {
this.myForm = this.fb.group({
lessonCode: "test",
answer:
What you need to do is to add emailCode
as FormArray
instead of FormControl
, this way you will be able to check whether the questionCode
already exists, and if yes, you can append to emailCode
the option you checked.
The only things to change are on your onChange
method
First you array
variable, you need to add FormArray
instead of FormControl
let array = new FormGroup({
questionCode: new FormControl(email),
emailCode: new FormArray([])
});
Then create a FormControl
for your checked option
let codeOption = new FormControl(code)
And finally, in your if
condition, check if the questionCode already exist to just append your formControl to it, or to create a new object.
if (isChecked) {
if (emailFormArray.controls.some(obj => obj.get('questionCode').value == email)){
(<FormArray>emailFormArray.controls.find(obj => obj.get('questionCode').value == email).get('emailCode')).push(codeOption);
}else{
(<FormArray>array.get('emailCode')).push(codeOption)
emailFormArray.push(array)
}
}
To be more clear I have modified your stackblitz to fit with your needs
I have not modified the else
condition to remove the options on your FormArray
but you just need to copy the if
condition to get the index of the code
element on your FormArray
of emailCode
.
You can make a function that traverses every answer and returns an object in your desired schema.
I suggested another aproach
If we create a formGroup like
this.myForm = this.fb.group({
lessonCode: "test",
answer: this.fb.array(this.users.map(x=>this.fb.group({
questionCode:x.code,
email:[[]]
})))
});
See that answer is a FormArray of FormGroup, each FormGroup has two FormsControl, questionCode and email, that is still a FormControl (but store an array). You need don't confussed with a FormArray. A FormControl can store an array, an object, an string, a number, etc.. And it's no so strange store an array, e.g. the mat-select multiple store an array too
As always we work with formArrays we declare a getter to manage in the .html
get answers()
{
return this.myForm.get('answer') as FormArray
}
Well, the form is a bit complex
<form [formGroup]="myForm">
<div formArrayName="answer">
<div *ngFor="let group of answers.controls;let i=index">
<p>{{users[i].code}}</p>
<div *ngFor="let user of users[i].email">
<input #check type="checkbox"
[value]="answers.at(i).value.email.indexOf(user.code)>=0"
(change)="onChange(i,user.code,check.checked)" >{{user.code}}<br>
</div>
</div>
</div>
</form>
See how we use [value]="answers.at(i).value.email.indexOf(user.code)>=0"
Really it's not necesary if our "email" control is at first empy, but it possible we want in a future use this form to show the result, and our "eamil" can value, e.g. "[option1]"
Another thing to take account is that I use a template reference variable #check
and send to the function OnChange check.checked
-so we received in the function a boolean-
Our function OnChange get more simple
onChange(index:number, code: string, isChecked: boolean) {
const control=this.answers.at(index).get('email')
if (isChecked && control.value.indexOf(code)<0)
control.setValue([...control.value,code]
.sort((a:string,b:string)=>
this.users[index].email.findIndex(x=>x.code==a)>
this.users[index].email.findIndex(x=>x.code==b)?1:-1)
)
if (!isChecked && control.value.indexOf(code)>=0)
control.setValue(control.value.filter(x=>x!=code))
}
I like check if exist or not before remove/add the element
See that we need "sort" the response when the check is true -else we received the response, e.g. [option2,option1] -If our requeriments don't required we can remove the sort-
The stackblitz