简体   繁体   中英

Get value from all checked checkbox in angular

i'm creating quiz app using angular and i have code like this

  ngOnInit() {
    this.myForm = this.fb.group({
      lessonCode: "test",
      answer: this.fb.array([])
    });
  }
  
  onChange(email: string, code: string, isChecked: boolean) {
    const emailFormArray = <FormArray>this.myForm.controls.answer;

    if (isChecked) {
      let array = new FormGroup({
        questionCode: new FormControl(email),
        emailCode: new FormArray([
          new FormControl(code)
        ]),
      });
      emailFormArray.push(array);
    } else {
      let index = emailFormArray.controls.findIndex(x => x.value == email);
      emailFormArray.removeAt(index);
    }
  }

在此处输入图片说明

which producing array like this

Form values: {
  "lessonCode": "test",
  "answer": [
    {
      "questionCode": "pertanyaan2",
      "emailCode": [
        "option2"
      ]
    },
    {
      "questionCode": "pertanyaan2",
      "emailCode": [
        "option1"
      ]
    }
  ]
}

but what i'm actually needed is like this

Form values: {
  "lessonCode": "test",
  "answer": [
    {
      "questionCode": "pertanyaan2",
      "emailCode": {
        "option2",
        "option1"
      }
    }
  ]
}

how can i achieve that? any thoughts would be very helpful

i have minimal reproduce here https://stackblitz.com/edit/angular-ca1jin?file=src%2Fapp%2Fapp.component.ts

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, eg 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, eg "[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, eg [option2,option1] -If our requeriments don't required we can remove the sort-

The stackblitz

您可以创建一个函数来遍历每个答案并以您想要的模式返回一个对象。

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM