ค้นหาเว็บไซต์

javascript - การผูกข้อมูลกับกล่องเลือกของ Angular


ฉันสามารถผูกข้อมูลจาก this.empDetails.services บน UI ได้อย่างถูกต้อง กล่องเลือกถูกเลือกอย่างถูกต้อง และยังแสดงตัวเลือกทั้งหมดของกล่องเลือกด้วย

อย่างไรก็ตาม ข้อมูลจะไม่ถูกส่งไปยัง serviceFormArray เมื่อฉันคลิกอัปเดตโดยไม่ทำการเปลี่ยนแปลงใด ๆ กับช่องทำเครื่องหมาย this.updateServicesForm.value จะว่างเปล่า

ฉันต้องยกเลิกการเลือกกล่องกาเครื่องหมายที่ถูกเลือกเหล่านั้นแล้วจึงเลือกมันอีกครั้งเพื่อให้มันส่งไปยัง formarray.

ฉันได้ลองเปลี่ยนแปลงอยู่เล็กน้อยแล้ว แต่ก็ไม่สำเร็จ มีใครสามารถแนะนำได้ไหมว่าโค้ดที่ถูกต้องเพื่อให้ได้สิ่งที่ฉันต้องการคืออะไร? ขอบคุณมาก 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>

ส่วนประกอบ 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);
  }

ข้อมูลจากการเรียก API this.empDetails.services

sservices: Array(2)
0: "mopping"
1: "washingclothes"
length: 2
__proto__: Array(0)

คำตอบ #1

เหตุผลสำหรับสิ่งนี้คือ คุณกำลังใช้ checked เพื่อทำเครื่องหมายว่าเช็คบ็อกซ์ใดควรถูกเลือก ซึ่งสิ่งเหล่านี้ไม่มีความสัมพันธ์กับอาร์เรย์ฟอร์มของคุณ ดังนั้นถ้าคุณไม่แตะเช็คบ็อกซ์ อาร์เรย์ฟอร์มจะว่างอย่างถูกต้อง

ฉันสามารถคิดตัวเลือกไม่กี่อย่างเพื่อแก้ปัญหานี้ได้... รวมถึงการเปลี่ยนแปลงดังต่อไปนี้:

ฟังก์ชัน change สามารถเปลี่ยนเป็นแบบนี้ได้:

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))
  }
}

ไม่สำคัญว่าคุณจะทำยังไง วิธีของคุณก็ใช้งานได้เหมือนกัน :) ฉันก็ชอบใช้ FormBuilder เช่นกัน (ที่นี่ถูกฉีดเป็น fb)

ฉันชอบใช้ getter ในกรณีนี้:

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

ตัวเลือกที่ฉันนึกออก:

  1. เพิ่มคุณสมบัติ checked ให้กับวัตถุในอาเรย์ sservicesOptions ของคุณ
  2. เก็บฟังก์ชัน isSelected ของคุณไว้ แต่ให้เพิ่มตัวเลือกที่เลือกไว้ลงใน formarray ของคุณในตอนแรก

ฉันชอบตัวเลือกที่ 1 มากที่สุด ดังนั้นให้เพิ่มคุณสมบัติ checked ลงในวัตถุ:

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 },
];

จากนั้นเมื่อคุณสร้างฟอร์ม ให้เปลี่ยนสถานะการเลือกสำหรับผู้ที่ควรถูกเลือกไว้ล่วงหน้า และเพิ่มค่าที่ควรถูกเลือกเข้าไปในอาเรย์ฟอร์มของคุณด้วย:

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)))
}

จากนั้นคุณสามารถเพิ่ม [checked]="service.checked" ในเทมเพลตได้

สาธิต

ตัวเลือก 2:

เก็บฟังก์ชัน checked ของคุณไว้แบบที่คุณมี แค่จำไว้ว่าให้เพิ่มค่าที่เลือกไว้ล่วงหน้าไปใน formarray ของคุณ ฉันไม่ค่อยชอบตัวเลือกนี้นัก เพราะตัวอย่างเช่น เราจะต้องเรียกฟังก์ชันในเทมเพลต ซึ่งจริงๆ แล้วไม่แนะนำ แต่ยังไงก็ตาม ให้เก็บโค้ดเหมือนที่คุณมีตอนนี้ แค่เพิ่มค่าตั้งต้นไปใน 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)))

สาธิต

ฉันเพิ่ม console.log ไว้ภายในฟังก์ชัน เพื่อแสดงว่ามันถูกเรียกอย่างไร มันโอเคสำหรับการสาธิตแบบนี้ แต่ถ้าคุณมีฟอร์มใหญ่ ฉันจะขอเตือนคุณจริงๆ ให้ใช้วิธีนี้

จะมีตัวเลือกที่สาม คือการตั้งค่าทุกค่าให้กับอาร์เรย์ฟอร์มของคุณจริง ๆ แล้วเพียงแค่สลับค่าบูลีนของกล่องกาเครื่องหมาย แต่สิ่งนั้นจะต้องมีการปรับโค้ดบางส่วน ซึ่งฉันไม่แน่ใจว่าคุณต้องการหรือไม่ แต่ก็ มี ตัวเลือกนั้นเช่นกัน

คำตอบ #2

คุณลืมตั้งค่าค่าใหม่ของฟอร์ม Array sservices :

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);
        break;
      }
      i++;
    });
  }
  // set the new value of sservices form array
  this.updateSvcForm.setControl('sservices', sservicesFormArray);
}

บทความที่เกี่ยวข้อง