-1

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?

1 Answer 1

2

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"]},
         ]
        )  
Sign up to request clarification or add additional context in comments.

7 Comments

i actually working this10 hours ago and i found the solution based on my stackblitz code, just playing and i got the result that i wanted, and it's similar to you final code, but i don't add the [checked]="answer.indexOf(option)>=0" is that okay? cause it seems work without it on my apps
and control.value.indexOf to me it gives me an error said that it's not a function, so i changed it to this control.value.toString().indexOf
the error is provoceted if "anwser" is null. It's correct conver to string or use [checked]="(answer || []).indexOf(option)>=0" -the "answer || []) main that if answer is null or undefined or "", take the value of an empty array
i see thats why u dont need toString
answer updated! :). BTW, in your code, after create the form, you neen't use the two loops to path, value. See that you give the value when create the form
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.