Angular ReactiveForms: Memproduksi array nilai kotak centang?

105

Diberikan daftar kotak centang yang terikat ke yang sama formControlName, bagaimana saya bisa menghasilkan larik nilai kotak centang yang terikat ke formControl, bukan hanya true/ false?

Contoh:

<form [formGroup]="checkboxGroup">
    <input type="checkbox" id="checkbox-1" value="value-1" formControlName="myValues" />
    <input type="checkbox" id="checkbox-2" value="value-2" formControlName="myValues" />
    <input type="checkbox" id="checkbox-3" value="value-2" formControlName="myValues" />
</form>

checkboxGroup.controls['myValues'].value saat ini memproduksi:

true or false

Apa yang saya ingin hasilkan:

['value-1', 'value-2', ...]
ReactingToAngularVues
sumber
apakah Anda menemukan solusi?
CP
Ini mungkin cara yang paling direkayasa untuk melakukan kotak centang di formulir yang pernah ada. Ini sama sekali tidak mudah.
mwilson
8
Angular. Yang saya coba lakukan adalah mendapatkan kelompok radio-mat untuk mengikat dalam bentuk reaktif saya. Saya tidak ingat berjuang sebanyak ini dengan sudut. Semua artikel mengarah pada hal yang sama. Tidak bisa membuatnya bekerja. Segala sesuatu yang lain sangat mudah. Saya mungkin telah melihatnya terlalu lama. Masih terasa seperti wayyyyy terlalu banyak kerumitan untuk nilai array dalam formulir.
mwilson
3
Ya itu mengerikan ketika saya menanyakan ini pada tahun 2016, dan itu masih buruk pada tahun 2019.
ReactingToAngularVues
3
Saya tidak menambahkan satu ton pun pada pertanyaan ini, tetapi saya ingin orang lain mengetahui bahwa saya merasakan hal yang sama. Ini sendiri telah menjadi bagian tersulit dalam mempelajari bentuk reaktif sudut. Saya merasa tidak sesulit ini, sama sekali. Saya senang melihat saya tidak sendirian dalam perjuangan ini. Terima kasih telah memposting pertanyaannya.
NorthStarCode

Jawaban:

51

Dengan bantuan jawaban silentsod, saya menulis solusi untuk mendapatkan nilai alih-alih status di formBuilder saya.

Saya menggunakan metode untuk menambah atau menghapus nilai di formArray. Ini mungkin pendekatan yang buruk, tetapi berhasil!

component.html

<div *ngFor="let choice of checks; let i=index" class="col-md-2">
  <label>
    <input type="checkbox" [value]="choice.value" (change)="onCheckChange($event)">
    {{choice.description}}
  </label>
</div>

component.ts

// For example, an array of choices
public checks: Array<ChoiceClass> = [
  {description: 'descr1', value: 'value1'},
  {description: "descr2", value: 'value2'},
  {description: "descr3", value: 'value3'}
];

initModelForm(): FormGroup{
  return this._fb.group({
    otherControls: [''],
    // The formArray, empty 
    myChoices: new FormArray([]),
  }
}

onCheckChange(event) {
  const formArray: FormArray = this.myForm.get('myChoices') as FormArray;

  /* Selected */
  if(event.target.checked){
    // Add a new control in the arrayForm
    formArray.push(new FormControl(event.target.value));
  }
  /* unselected */
  else{
    // find the unselected element
    let i: number = 0;

    formArray.controls.forEach((ctrl: FormControl) => {
      if(ctrl.value == event.target.value) {
        // Remove the unselected element from the arrayForm
        formArray.removeAt(i);
        return;
      }

      i++;
    });
  }
}

Saat saya mengirimkan formulir saya, misalnya model saya terlihat seperti:

  otherControls : "foo",
  myChoices : ['value1', 'value2']

Hanya satu hal yang hilang, fungsi untuk mengisi formArray jika model Anda sudah memeriksa nilai.

Guymage
sumber
bagaimana cara memeriksa apakah kotak centang saya dicentang ketika saya memuat data setelah menggunakan contoh Anda untuk masuk ke db?
Devora
Dalam solusi ini selalu formulir itu valid meskipun kotak centang tidak dipilih
Teja
myChoices: new FormArray([], Validators.required)
Bikram Nath
"Tapi berhasil!" adalah bagaimana utang teknologi dimulai. Ini bukanlah cara bentuk reaktif untuk melakukannya. Salah satu keuntungan menggunakan formcontrols pada setiap masukan kotak centang adalah mereka dapat mengingat statusnya bahkan saat Anda menambahkannya kembali ke DOM.
MIWMIB
50

Ini tempat yang bagus untuk menggunakan file FormArray https://angular.io/docs/ts/latest/api/forms/index/FormArray-class.html

Untuk memulai kita akan membangun berbagai kontrol kita baik dengan a FormBuilderatau yang baru aFormArray

FormBuilder

this.checkboxGroup = _fb.group({
  myValues: _fb.array([true, false, true])
});

FormArray baru

let checkboxArray = new FormArray([
  new FormControl(true),
  new FormControl(false),
  new FormControl(true)]);

this.checkboxGroup = _fb.group({
  myValues: checkboxArray
});

Cukup mudah untuk dilakukan, tetapi kemudian kita akan mengubah template kita dan membiarkan mesin template menangani bagaimana kita mengikat kontrol kita:

template.html

<form [formGroup]="checkboxGroup">
    <input *ngFor="let control of checkboxGroup.controls['myValues'].controls"
    type="checkbox" id="checkbox-1" value="value-1" [formControl]="control" />     
  </form>

Di sini kami mengulangi set kami FormControlsdi kami myValues FormArraydan untuk setiap kontrol kami mengikat [formControl]kontrol itu alih-alih ke FormArraykontrol dan <div>{{checkboxGroup.controls['myValues'].value}}</div>produksitrue,false,true sementara juga membuat sintaks template Anda sedikit lebih manual.

Anda dapat menggunakan contoh ini: http://plnkr.co/edit/a9OdMAq2YIwQFo7gixbj?p=preview untuk melihat-lihat

diam
sumber
1
mungkin Anda harus menghapus id = "xxx", id harus unik kan?
PeiSong Xiong
1
untuk id dapat digunakan indeks *ngFor="let control of checkboxGroup.controls['myValues'].controls ; let i=index""
Mirza
9
Ini keren, tetapi menghasilkan deretan kotak centang yang sepenuhnya umum. Agaknya Anda akan memuat dalam sebuah array atau sesuatu yang lain, dan mengaitkan setiap kotak centang dengan beberapa nilai lain. Bagaimana Anda menambahkan, misalnya, string teks untuk digunakan dalam label formulir ke setiap kontrol formulir?
Askdesigners
NM Saya baru saja memetakannya di sebelah array eksternal: p
Askdesigners
@Askdesigners Dapatkah Anda memposting solusi Anda untuk mendapatkan kotak centang dan label?
eddygeek
26

Ini jauh lebih mudah untuk melakukan ini di Angular 6 daripada di versi sebelumnya, bahkan ketika informasi kotak centang diisi secara asinkron dari API.

Hal pertama yang harus disadari adalah bahwa berkat keyvaluepipa Angular 6 kita tidak perlu menggunakan FormArraylagi, dan sebagai gantinya dapat membuat sarang a FormGroup.

Pertama, teruskan FormBuilder ke konstruktor

constructor(
    private _formBuilder: FormBuilder,
) { }

Kemudian inisialisasi formulir kita.

ngOnInit() {

    this.form = this._formBuilder.group({
        'checkboxes': this._formBuilder.group({}),
    });

}

Saat data opsi kotak centang kami tersedia, lakukan iterasi dan kami dapat mendorongnya langsung ke dalam nested FormGroupsebagai nama FormControl, tanpa harus bergantung pada array pencarian indeks nomor.

const checkboxes = <FormGroup>this.form.get('checkboxes');
options.forEach((option: any) => {
    checkboxes.addControl(option.title, new FormControl(true));
});

Terakhir, dalam template kita hanya perlu mengulang keyvaluekotak centang: tidak ada tambahan let index = i, dan kotak centang secara otomatis akan berada dalam urutan abjad: jauh lebih bersih.

<form [formGroup]="form">

    <h3>Options</h3>

    <div formGroupName="checkboxes">

        <ul>
            <li *ngFor="let item of form.get('checkboxes').value | keyvalue">
                <label>
                    <input type="checkbox" [formControlName]="item.key" [value]="item.value" /> {{ item.key }}
                </label>
            </li>
        </ul>

    </div>

</form>
Danny Pritchard
sumber
1
Sangat berguna juga dalam kasus array nilai kotak centang hardcode sederhana. Kemudian Anda dapat menambahkan kontrol formulir menggunakan perulangan for yang serupa langsung di ngOnInit (), dan kotak centang di formulir Anda akan secara dinamis mencerminkan larik nilai kotak centang
Arjan
3
Ini masih mengutip [key1 = true, key2 = false, key3 = true]. Kami ingin ['key1', 'key3']
f.khantsis
@ f.khantsis Anda dapat melakukannya seperti itu: `const value = {key1: true, key2: false, key3: true}; daftar const = Object.entries (nilai) .filter (([_, isSelected]) => isSelected) .map (([key]) => key); console.log (daftar); `
zauni
2
Solusi terbaik imho. Anda dapat menempatkan tugas di const checkboxes = ..luar depan;)
Bernoulli IT
Apa yang terjadi jika kunci item sama dengan bidang lain di formulir? Misalnya, saya memiliki dua array kotak centang yang berbeda, masing-masing dengan tombol 'Kecil', 'Sedang', dan 'Besar'?
Newclique
9

Jika Anda mencari nilai kotak centang dalam format JSON

{ "name": "", "countries": [ { "US": true }, { "Germany": true }, { "France": true } ] }

Contoh lengkapnya di sini .

Saya minta maaf karena menggunakan Nama Negara sebagai nilai kotak centang daripada yang ada dalam pertanyaan. Penjelasan lebih lanjut -

Buat FormGroup untuk formulir

 createForm() {

    //Form Group for a Hero Form
    this.heroForm = this.fb.group({
      name: '',
      countries: this.fb.array([])
    });

    let countries=['US','Germany','France'];

    this.setCountries(countries);}
 }

Biarkan setiap kotak centang menjadi Grup Form yang dibangun dari objek yang satu-satunya properti adalah nilai kotak centang.

 setCountries(countries:string[]) {

    //One Form Group for one country
    const countriesFGs = countries.map(country =>{
            let obj={};obj[country]=true;
            return this.fb.group(obj)
    });

    const countryFormArray = this.fb.array(countriesFGs);
    this.heroForm.setControl('countries', countryFormArray);
  }

Array FormGroups untuk kotak centang digunakan untuk mengatur kontrol untuk 'negara' di Formulir induk.

  get countries(): FormArray {
      return this.heroForm.get('countries') as FormArray;
  };

Di template, gunakan pipa untuk mendapatkan nama kontrol kotak centang

  <div formArrayName="countries" class="well well-lg">
      <div *ngFor="let country of countries.controls; let i=index" [formGroupName]="i" >
          <div *ngFor="let key of country.controls | mapToKeys" >
              <input type="checkbox" formControlName="{{key.key}}">{{key.key}}
          </div>
      </div>
  </div>
asam
sumber
7

Saya tidak melihat solusi di sini yang sepenuhnya menjawab pertanyaan menggunakan formulir reaktif sepenuhnya jadi inilah solusi saya untuk hal yang sama.


Ringkasan

Berikut inti dari penjelasan mendetail bersama dengan contoh StackBlitz.

  1. Menggunakan FormArray untuk kotak centang dan inisialisasi formulir.
  2. The valueChangesdiamati adalah sempurna untuk ketika Anda ingin bentuk untuk tampilan sesuatu tapi toko sesuatu yang lain dalam komponen tersebut. Petakan true/false values ​​ke nilai yang diinginkan di sini.
  3. Saring file false nilainya pada saat pengiriman.
  4. Berhenti berlangganan dari valueChangesobservable.

Contoh StackBlitz


Penjelasan detail

Gunakan FormArray untuk menentukan formulir

Seperti yang sudah disebutkan dalam jawaban ditandai sebagai benar. FormArrayadalah cara untuk pergi dalam kasus seperti itu di mana Anda lebih suka mendapatkan data dalam larik. Jadi, hal pertama yang perlu Anda lakukan adalah membuat formulir.

checkboxGroup: FormGroup;
checkboxes = [{
    name: 'Value 1',
    value: 'value-1'
}, {
    name: 'Value 2',
    value: 'value-2'
}];

this.checkboxGroup = this.fb.group({
    checkboxes: this.fb.array(this.checkboxes.map(x => false))
});

Ini hanya akan menyetel nilai awal semua kotak centang menjadi false.

Selanjutnya, kita perlu mendaftarkan variabel formulir ini di template dan melakukan iterasi di atas checkboxesarray (BUKAN FormArraydata kotak centang tapi) untuk menampilkannya di template.

<form [formGroup]="checkboxGroup">
    <ng-container *ngFor="let checkbox of checkboxes; let i = index" formArrayName="checkboxes">
        <input type="checkbox" [formControlName]="i" />{{checkbox.name}}
    </ng-container>
</form>

Manfaatkan valueChanges yang dapat diamati

Inilah bagian yang saya tidak lihat disebutkan dalam jawaban apa pun yang diberikan di sini. Dalam situasi seperti ini, di mana kami ingin menampilkan data tersebut tetapi menyimpannya sebagai sesuatu yang lain, valueChangesobservable sangat membantu. Menggunakan valueChanges, kita dapat mengamati perubahan checkboxesdan kemudian mapyang true/ falsenilai-nilai yang diterima dari FormArraydata yang diinginkan. Perhatikan bahwa ini tidak akan mengubah pemilihan kotak centang karena nilai kebenaran apa pun yang diteruskan ke kotak centang akan menandainya sebagai dicentang dan sebaliknya.

subscription: Subscription;

const checkboxControl = (this.checkboxGroup.controls.checkboxes as FormArray);
this.subscription = checkboxControl.valueChanges.subscribe(checkbox => {
    checkboxControl.setValue(
        checkboxControl.value.map((value, i) => value ? this.checkboxes[i].value : false),
        { emitEvent: false }
    );
});

Ini pada dasarnya memetakan FormArraynilai ke checkboxesarray asli dan mengembalikan valueseandainya kotak centang ditandai sebagai true, jika tidak maka akan dikembalikan false. Di emitEvent: falsesini penting karena menyetel FormArraynilai tanpanya akan menyebabkan valueChangesterjadinya peristiwa yang membuat pengulangan tanpa akhir. Dengan menyetel emitEventke false, kami memastikan valueChangesobservable tidak memancarkan saat kami menyetel nilainya di sini.

Filter nilai yang salah

Kita tidak dapat secara langsung memfilter falsenilai di dalam FormArraykarena hal itu akan mengacaukan template karena terikat ke kotak centang. Jadi, solusi terbaik adalah menyaring falsenilai selama pengiriman. Gunakan operator penyebaran untuk melakukan ini.

submit() {
    const checkboxControl = (this.checkboxGroup.controls.checkboxes as FormArray);
    const formValue = {
        ...this.checkboxGroup.value,
        checkboxes: checkboxControl.value.filter(value => !!value)
    }
    // Submit formValue here instead of this.checkboxGroup.value as it contains the filtered data
}

Ini pada dasarnya menyaring nilai-nilai palsu dari file checkboxes.

Berhenti berlangganan valueChanges

Terakhir, jangan lupa berhenti berlangganan valueChanges

ngOnDestroy() {
    this.subscription.unsubscribe();
}

Catatan: Ada kasus khusus di mana nilai tidak dapat disetel ke FormArraydalam valueChanges, yaitu jika nilai kotak centang disetel ke angka 0. Ini akan membuatnya tampak seperti kotak centang tidak dapat dipilih karena memilih kotak centang akan menetapkan FormControlsebagai nomor 0(nilai palsu) dan karenanya tetap tidak dicentang. Ini akan lebih disukai untuk tidak menggunakan angka 0sebagai nilai tetapi jika diperlukan, Anda harus mengatur secara kondisional 0ke beberapa nilai yang benar, katakanlah string '0'atau hanya polos truedan kemudian saat mengirimkan, ubah kembali menjadi angka 0.

Contoh StackBlitz

StackBlitz juga memiliki kode ketika Anda ingin meneruskan nilai default ke kotak centang sehingga mereka ditandai sebagai dicentang di UI.

nash11
sumber
Ini masih membutuhkan pemeliharaan dua larik dan menjaganya tetap sinkron. Masih belum sebersih yang kuharapkan. Mungkin kita bisa mendapatkan kontrol formulir untuk menyimpan nilai kompleks daripada memiliki dua larik.
MIWMIB
1
Nilai kompleks tidak berfungsi karena nilainya harus benar atau salah untuk kotak centang. Jadi solusi ini masih terlihat yang terbaik.
MIWMIB
6

TL; DR

  1. Saya lebih suka menggunakan FormGroup untuk mengisi daftar kotak centang
  2. Tulis validator khusus untuk memeriksa setidaknya satu kotak centang dipilih
  3. Contoh kerja https://stackblitz.com/edit/angular-validate-at-least-one-checkbox-was-selected

Ini juga mengejutkan saya untuk kadang-kadang jadi saya mencoba pendekatan FormArray dan FormGroup.

Sebagian besar waktu, daftar kotak centang diisi di server dan saya menerimanya melalui API. Tetapi terkadang Anda akan memiliki sekumpulan kotak centang statis dengan nilai yang telah Anda tentukan sebelumnya. Dengan setiap kasus penggunaan, FormArray atau FormGroup yang sesuai akan digunakan.

Pada dasarnya FormArrayadalah varian dari FormGroup. Perbedaan utamanya adalah bahwa datanya diserialkan sebagai array (sebagai lawan menjadi serial sebagai objek dalam kasus FormGroup). Ini mungkin berguna terutama ketika Anda tidak mengetahui berapa banyak kontrol yang akan ada dalam grup, seperti formulir dinamis.

Demi kesederhanaan, bayangkan Anda memiliki bentuk produk buat sederhana dengan

  • Satu kotak teks nama produk yang diperlukan.
  • Daftar kategori untuk dipilih, membutuhkan setidaknya satu untuk diperiksa. Asumsikan daftar tersebut akan diambil dari server.

Pertama, saya menyiapkan formulir hanya dengan nama produk formControl. Ini adalah bidang yang wajib diisi.

this.form = this.formBuilder.group({
    name: ["", Validators.required]
});

Karena kategori dirender secara dinamis, saya harus menambahkan data ini ke dalam formulir nanti setelah data siap.

this.getCategories().subscribe(categories => {
    this.form.addControl("categoriesFormArr", this.buildCategoryFormArr(categories));
    this.form.addControl("categoriesFormGroup", this.buildCategoryFormGroup(categories));
})

Ada dua pendekatan untuk menyusun daftar kategori.

1. Bentuk Array

  buildCategoryFormArr(categories: ProductCategory[], selectedCategoryIds: string[] = []): FormArray {
    const controlArr = categories.map(category => {
      let isSelected = selectedCategoryIds.some(id => id === category.id);
      return this.formBuilder.control(isSelected);
    })
    return this.formBuilder.array(controlArr, atLeastOneCheckboxCheckedValidator())
  }
<div *ngFor="let control of categoriesFormArr?.controls; let i = index" class="checkbox">
  <label><input type="checkbox" [formControl]="control" />
    {{ categories[i]?.title }}
  </label>
</div>

Ini buildCategoryFormGroupakan mengembalikan saya sebuah FormArray. Ini juga mengambil daftar nilai yang dipilih sebagai argumen jadi Jika Anda ingin menggunakan kembali formulir untuk mengedit data, ini bisa membantu. Untuk tujuan membuat bentuk produk baru, ini belum bisa diterapkan.

Tercatat ketika Anda mencoba mengakses nilai formArray. Ini akan terlihat seperti [false, true, true]. Untuk mendapatkan daftar id yang dipilih, dibutuhkan sedikit lebih banyak pekerjaan untuk memeriksa dari daftar tetapi berdasarkan indeks array. Kedengarannya tidak bagus bagi saya, tetapi berhasil.

get categoriesFormArraySelectedIds(): string[] {
  return this.categories
  .filter((cat, catIdx) => this.categoriesFormArr.controls.some((control, controlIdx) => catIdx === controlIdx && control.value))
  .map(cat => cat.id);
}

Itulah mengapa saya datang menggunakan FormGroupmasalah itu

2. Bentuk Kelompok

Perbedaan dari formGroup adalah akan menyimpan data form sebagai objek, yang membutuhkan key dan form control. Jadi adalah ide yang bagus untuk menyetel kunci sebagai categoryId dan kemudian kita bisa mengambilnya nanti.

buildCategoryFormGroup(categories: ProductCategory[], selectedCategoryIds: string[] = []): FormGroup {
  let group = this.formBuilder.group({}, {
    validators: atLeastOneCheckboxCheckedValidator()
  });
  categories.forEach(category => {
    let isSelected = selectedCategoryIds.some(id => id === category.id);
    group.addControl(category.id, this.formBuilder.control(isSelected));
  })
  return group;
}
<div *ngFor="let item of categories; let i = index" class="checkbox">
  <label><input type="checkbox" [formControl]="categoriesFormGroup?.controls[item.id]" /> {{ categories[i]?.title }}
  </label>
</div>

Nilai grup formulir akan terlihat seperti ini:

{
    "category1": false,
    "category2": true,
    "category3": true,
}

Namun paling sering kami hanya ingin mendapatkan daftar categoryIds sebagai ["category2", "category3"]. Saya juga harus menulis untuk mengambil data ini. Saya lebih menyukai pendekatan ini dibandingkan dengan formArray, karena saya sebenarnya dapat mengambil nilai dari formulir itu sendiri.

  get categoriesFormGroupSelectedIds(): string[] {
    let ids: string[] = [];
    for (var key in this.categoriesFormGroup.controls) {
      if (this.categoriesFormGroup.controls[key].value) {
        ids.push(key);
      }
      else {
        ids = ids.filter(id => id !== key);
      }
    }
    return ids;
  }

3. Validator khusus untuk memeriksa setidaknya satu kotak centang dipilih

Saya membuat validator untuk memeriksa setidaknya X kotak centang dipilih, secara default hanya akan memeriksa satu kotak centang.

export function atLeastOneCheckboxCheckedValidator(minRequired = 1): ValidatorFn {
  return function validate(formGroup: FormGroup) {
    let checked = 0;

    Object.keys(formGroup.controls).forEach(key => {
      const control = formGroup.controls[key];

      if (control.value === true) {
        checked++;
      }
    });

    if (checked < minRequired) {
      return {
        requireCheckboxToBeChecked: true,
      };
    }

    return null;
  };
}
trungk18
sumber
4

Buat acara saat diklik lalu ubah nilai true secara manual ke nama yang diwakili oleh kotak centang, lalu nama atau true akan dievaluasi sama dan Anda bisa mendapatkan semua nilai alih-alih daftar true / false. Ex:

component.html

<form [formGroup]="customForm" (ngSubmit)="onSubmit()">
    <div class="form-group" *ngFor="let parameter of parameters"> <!--I iterate here to list all my checkboxes -->
        <label class="control-label" for="{{parameter.Title}}"> {{parameter.Title}} </label>
            <div class="checkbox">
              <input
                  type="checkbox"
                  id="{{parameter.Title}}"
                  formControlName="{{parameter.Title}}"
                  (change)="onCheckboxChange($event)"
                  > <!-- ^^THIS^^ is the important part -->
             </div>
      </div>
 </form>

component.ts

onCheckboxChange(event) {
    //We want to get back what the name of the checkbox represents, so I'm intercepting the event and
    //manually changing the value from true to the name of what is being checked.

    //check if the value is true first, if it is then change it to the name of the value
    //this way when it's set to false it will skip over this and make it false, thus unchecking
    //the box
    if(this.customForm.get(event.target.id).value) {
        this.customForm.patchValue({[event.target.id] : event.target.id}); //make sure to have the square brackets
    }
}

Ini menangkap acara setelah itu sudah diubah menjadi benar atau salah oleh Bentuk Sudut, jika itu benar saya mengubah nama ke nama yang diwakili oleh kotak centang, yang jika diperlukan juga akan mengevaluasi ke benar jika itu diperiksa benar / salah sebagai baik.

kanada11
sumber
Ini membawa saya ke jalur yang benar, saya akhirnya melakukan ini.customForm.patchValue ({[event.target.id]: event.target.checked});
Demodave
4

Jika Anda ingin menggunakan bentuk reaktif Angular ( https://angular.io/guide/reactive-forms ).

Anda dapat menggunakan satu kontrol formulir untuk mengelola nilai yang dikeluarkan dari grup kotak centang.

komponen

import { Component } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { flow } from 'lodash';
import { flatMap, filter } from 'lodash/fp';

@Component({
  selector: 'multi-checkbox',
  templateUrl: './multi-checkbox.layout.html',
})
export class MultiChecboxComponent  {

  checklistState = [ 
      {
        label: 'Frodo Baggins',
        value: 'frodo_baggins',
        checked: false
      },
      {
        label: 'Samwise Gamgee',
        value: 'samwise_gamgee',
        checked: true,
      },
      {
        label: 'Merry Brandybuck',
        value: 'merry_brandybuck',
        checked: false
      }
    ];

  form = new FormGroup({
    checklist : new FormControl(this.flattenValues(this.checklistState)),
  });


  checklist = this.form.get('checklist');

  onChecklistChange(checked, checkbox) {
    checkbox.checked = checked;
    this.checklist.setValue(this.flattenValues(this.checklistState));
  }

  flattenValues(checkboxes) {
    const flattenedValues = flow([
      filter(checkbox => checkbox.checked),
      flatMap(checkbox => checkbox.value )
    ])(checkboxes)
    return flattenedValues.join(',');
  }
}

html

<form [formGroup]="form">
    <label *ngFor="let checkbox of checklistState" class="checkbox-control">
    <input type="checkbox" (change)="onChecklistChange($event.target.checked, checkbox)" [checked]="checkbox.checked" [value]="checkbox.value" /> {{ checkbox.label }}
  </label>
</form>

checklistState

Mengelola model / status input daftar periksa. Model ini memungkinkan Anda untuk memetakan keadaan saat ini ke format nilai apa pun yang Anda butuhkan.

Model:

{
   label: 'Value 1',
   value: 'value_1',
   checked: false
},
{
  label: 'Samwise Gamgee',
  value: 'samwise_gamgee',
  checked: true,
},
{
  label: 'Merry Brandybuck',
  value: 'merry_brandybuck',
  checked: false
}

checklist Kontrol Formulir

Kontrol ini menyimpan nilai yang ingin disimpan sebagai mis

keluaran nilai: "value_1,value_2"

Lihat demo di https://stackblitz.com/edit/angular-multi-checklist

Robert Prib
sumber
Mudah menjadi solusi terbaik untuk saya. Terima kasih banyak.
Newclique
2

Solusi saya - memecahkannya untuk Angular 5 dengan Material View
Sambungannya melalui

formArrayName = "notifikasi"

(ubah) = "updateChkbxArray (n.id, $ event.checked, 'notification')"

Dengan cara ini dapat bekerja untuk beberapa array kotak centang dalam satu bentuk. Cukup atur nama array kontrol untuk menghubungkan setiap waktu.

constructor(
  private fb: FormBuilder,
  private http: Http,
  private codeTableService: CodeTablesService) {

  this.codeTableService.getnotifications().subscribe(response => {
      this.notifications = response;
    })
    ...
}


createForm() {
  this.form = this.fb.group({
    notification: this.fb.array([])...
  });
}

ngOnInit() {
  this.createForm();
}

updateChkbxArray(id, isChecked, key) {
  const chkArray = < FormArray > this.form.get(key);
  if (isChecked) {
    chkArray.push(new FormControl(id));
  } else {
    let idx = chkArray.controls.findIndex(x => x.value == id);
    chkArray.removeAt(idx);
  }
}
<div class="col-md-12">
  <section class="checkbox-section text-center" *ngIf="notifications  && notifications.length > 0">
    <label class="example-margin">Notifications to send:</label>
    <p *ngFor="let n of notifications; let i = index" formArrayName="notification">
      <mat-checkbox class="checkbox-margin" (change)="updateChkbxArray(n.id, $event.checked, 'notification')" value="n.id">{{n.description}}</mat-checkbox>
    </p>
  </section>
</div>

Pada akhirnya Anda bisa menyimpan formulir dengan array id catatan asli untuk disimpan / diperbarui. Tampilan UI

Bagian yang relevan dari json formulir

Akan dengan senang hati memberikan komentar untuk perbaikan.

Tzvi Gregory Kaidanov
sumber
0

BAGIAN TEMPLATE: -

    <div class="form-group">
         <label for="options">Options:</label>
         <div *ngFor="let option of options">
            <label>
                <input type="checkbox"
                   name="options"
                   value="{{option.value}}"
                   [(ngModel)]="option.checked"
                                />
                  {{option.name}}
                  </label>
              </div>
              <br/>
         <button (click)="getselectedOptions()"  >Get Selected Items</button>
     </div>

BAGIAN PENGONTROL: -

        export class Angular2NgFor {

          constructor() {
             this.options = [
              {name:'OptionA', value:'first_opt', checked:true},
              {name:'OptionB', value:'second_opt', checked:false},
              {name:'OptionC', value:'third_opt', checked:true}
             ];


             this.getselectedOptions = function() {
               alert(this.options
                  .filter(opt => opt.checked)
                  .map(opt => opt.value));
                }
             }

        }
Abhishek Srivastava
sumber
1
Hai @EchoLogic .. Harap beri tahu saya jika ada pertanyaan
Abhishek Srivastava
1
Ini tidak menggunakan ReactiveForms tetapi formulir biasa jadi tidak menjawab pertanyaan
Guillaume
0

Tambahkan 5 sen saya) Model pertanyaan saya

{
   name: "what_is_it",
   options:[
     {
      label: 'Option name',
      value: '1'
     },
     {
      label: 'Option name 2',
      value: '2'
     }
   ]
}

template.html

<div class="question"  formGroupName="{{ question.name }}">
<div *ngFor="let opt of question.options; index as i" class="question__answer" >
  <input 
    type="checkbox" id="{{question.name}}_{{i}}"
    [name]="question.name" class="hidden question__input" 
    [value]="opt.value" 
    [formControlName]="opt.label"
   >
  <label for="{{question.name}}_{{i}}" class="question__label question__label_checkbox">
      {{opt.label}}
  </label>
</div>

component.ts

 onSubmit() {
    let formModel = {};
    for (let key in this.form.value) {
      if (typeof this.form.value[key] !== 'object') { 
        formModel[key] = this.form.value[key]
      } else { //if formgroup item
        formModel[key] = '';
        for (let k in this.form.value[key]) {
          if (this.form.value[key][k])
            formModel[key] = formModel[key] + k + ';'; //create string with ';' separators like 'a;b;c'
        }
      }
    }
     console.log(formModel)
   }
Chemaxa
sumber