Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
140 views
in Technique[技术] by (71.8m points)

javascript - binding data to angular checkbox

I managed to bind the data from this.empDetails.services correctly on the UI, checkboxes are checked correctly, and also listed all the checkboxes options.

However, the data are not pushed to the serviceFormArray, when I click update without any changes to the checkbox, this.updateServicesForm.value is empty.

I have to uncheck those checked checkboxes and then check it again so that it will push to the formarray.

I tried a few changes, but to no avail, can someone suggest what is the correct code to archived what I need? Thank you so much. HTML

<form action="javascript:" [formGroup]="updateSvcForm">
  <div class="row" *ngFor="let service of servicesOptions; let i=index">
    <div class="col-sm-12">
      <div class="checkbox-color checkbox-primary">
        <input type="checkbox" id={{service.value}} [value]="service.value" (change)="onCheckChange($event)" [checked]=isSelected(service.value)>
        <label for={{service.value}}>
          {{service.description}}
        </label>
      </div>
    </div>
  </div>
  <div class="form-group row">
    <label class="col-sm-2"></label>
    <div class="col-sm-10">
      <button class="btn btn-primary m-b-0 ripple light" (click)="updateServices()">Update</button>
    </div>
  </div>
</form>

Component.TS

sservicesOptions = [
  { description: '1. Sweeping', value: 'sweeping' },
  { description: '2. Mopping', value: 'mopping' },
  { description: '3. Windows', value: 'windows' },
  { description: '4. Washing Clothes', value: 'washingclothes' },
];


this.updateSvcForm= this.fb.group({
  sservices: new FormArray([]),
});

onCheckChange(event) {
  const sservicesFormArray: FormArray =
    this.updateSvcForm.get('sservices') as FormArray;


  if (event.target.checked) {
    sservicesFormArray.push(new FormControl(event.target.value));
  }
  else {
    let i: number = 0;
    sservicesFormArray.controls.forEach((ctrl: FormControl) => {
      if (ctrl.value == event.target.value) {
        sservicesFormArray.removeAt(i);
        return;
      }
      i++;
    });
  }
}

isSelected(sserviceOption) {
  return this.empDetails.services.indexOf(serviceOption) >= 0;
}
    console.log(this.updateSvcForm.value);
  }

Data from this.empDetails.services API return

sservices: Array(2)
0: "mopping"
1: "washingclothes"
length: 2
__proto__: Array(0)
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The reason for this, is that you are using checked to mark which checkboxes should be checked, they have no correlation to your form array, so if you do not touch the checkboxes, the formarray will correctly be empty.

I can come up with a couple options to solve this... also the following changes:

change function could be changed to this:

onCheckChange(event) {
  if (event.target.checked) {
    this.ssArray.push(this.fb.control(event.target.value));
  }
  else {
   this.ssArray.removeAt(this.ssArray.value.findIndex(x => x === event.target.value))
  }
}

Doesn't matter how you do it, your way works as well :) I also like using FormBuilder (here injected as fb).

I like to use a getter in this case:

get ssArray() {
  return this.updateSvcForm.get('sservices') as FormArray;
}

The options I can think of:

  1. add a checked property to the objects in your array sservicesOptions
  2. Keep your isSelected function, but add the chosen options to your formarray initially

I like option 1 best, so add a checked property to the objects:

servicesOptions = [
  { description: '1. Sweeping', value: 'sweeping', checked: false },
  { description: '2. Mopping', value: 'mopping', checked: false },
  { description: '3. Windows', value: 'windows', checked: false },
  { description: '4. Washing Clothes', value: 'washingclothes', checked: false },
];

Then when you build the form, change the checked status for those that should be preselected, and also add the values that should be checked to your form array:

constructor(private fb: FormBuilder) {
  this.updateSvcForm = this.fb.group({
    sservices: this.fb.array([]),
  });
  // change the checked status for the checkboxes that should be checked
  this.servicesOptions.map(x => 
    this.empDetails.services.indexOf(x) >= 0 ? x.checked = true : x.checked = false)
  // initially set the selected form controls to the formarray
  this.empDetails.services.map((x) => this.ssArray.push(this.fb.control(x)))
}

Then you can add [checked]="service.checked" in template.

DEMO


Option 2:

Keep your checked function like you have, just remember to add the prechosen values to your formarray. I don't really like this option, since for example, we end up calling a function in template, which is really not recommended. But anyway, keep the code as the same as you have now, just add the intial values to the formarray:

this.updateSvcForm = this.fb.group({
  sservices: this.fb.array([]),
});
// add the intial values to the formarray:
this.empDetails.services.map((x) => this.ssArray.push(this.fb.control(x)))

DEMO

I added a console.log inside the function, to show how it is called. It's okay for a demo like this, but if you have a big form, I would really caution for you to use this solution.


There would be a third option, to actually set all values to your form array, and then just toggle the boolean value of the checkbox, but that would require some refactoring of code, which I don't know if you want. But there is that option too.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...