Angular ReactiveForms: Bir dizi onay kutusu değeri mi üretiyorsunuz?


109

Aynı şekilde bağlanmış onay kutularının bir listesi verildiğinde , basitçe / yerine formControlNameöğesine bağlı bir onay kutusu değerleri dizisini nasıl üretebilirim ?formControltruefalse

Misal:

<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 şu anda üretir:

true or false

Üretmesini istediğim şey:

['value-1', 'value-2', ...]

herhangi bir çözüm buldun mu?
CP

Bu, muhtemelen şimdiye kadar bir biçimde onay kutuları yapmanın en fazla mühendislik yöntemidir. Bu hiç de kolay değil.
mwilson

8
Açısal. Tek yapmaya çalıştığım şey, reaktif formuma bağlanacak bir mat-radyo grubu almak. Açısal ile bu kadar mücadele ettiğimi hatırlamıyorum. Tüm makaleler aynı şeye işaret ediyor. Sadece çalıştıramıyorum. Geri kalan her şey çok basit. Muhtemelen ona çok uzun zamandır bakıyorum. Yine de, bir formdaki bir dizi değeri için çok fazla karmaşıklık gibi geliyor.
mwilson

3
Evet, bunu 2016'da sorduğumda korkunçtu ve 2019'da hala korkunç.
ReactingToAngularVues

3
Bu soruya bir ton eklemiyorum ama aynı şekilde hissettiğimi başkalarına da bilmesini istedim. Bu tek başına açısal tepkisel formları öğrenmenin en zor kısmı olmuştur. Hiç de bu kadar zor olmaması gerektiğini hissediyorum. Yine de mücadelede yalnız olmadığımı görmekten mutluyum. Soruyu gönderdiğiniz için teşekkürler.
NorthStarCode

Yanıtlar:


55

Silentsod cevabının yardımıyla formBuilder'ımda durumlar yerine değerler elde etmek için bir çözüm yazdım.

FormArray'e değer eklemek veya kaldırmak için bir yöntem kullanıyorum. Kötü bir yaklaşım olabilir ama işe yarıyor!

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

Formumu gönderdiğimde, örneğin modelim şöyle görünüyor:

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

Tek bir şey eksik, modeliniz zaten değerleri kontrol ettiyse formArray'i doldurmak için bir işlev.


Örneğinizi db'ye girmek için kullandıktan sonra verileri yüklediğimde onay kutumun işaretli olup olmadığını nasıl kontrol ederim?
Devora

Bu çözümde, onay kutusu seçili olmasa bile form her zaman geçerlidir
Teja

myChoices: new FormArray([], Validators.required)
Bikram Nath

"Ama işe yarıyor!" teknoloji borcunun nasıl başladığıdır. Bunu yapmanın reaktif şekli bu değil. Her onay kutusu girişinde form kontrollerini kullanmanın avantajlarından biri, bunları DOM'a yeniden eklediğinizde bile durumlarını hatırlayabilmeleridir.
MIWMIB

51

İşte https://angular.io/docs/ts/latest/api/forms/index/FormArray-class.html kullanmak için iyi bir yerFormArray

Başlamak için, kontroller FormBuilderdizimizi bir veya yenisiyle oluşturacağız.FormArray

FormBuilder

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

yeni FormArray

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

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

Yapması yeterince kolay, ama sonra şablonumuzu değiştireceğiz ve şablon motorunun kontrollerimize nasıl bağlandığımızı halletmesine izin vereceğiz:

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>

Burada bizim sette taraftalar ilerlerken FormControlsbizim içinde myValues FormArrayve her kontrol için biz bağlayıcı ediyoruz [formControl]o kontrole yerine göre FormArraykontrol ve <div>{{checkboxGroup.controls['myValues'].value}}</div>üretir true,false,trueda biraz daha az manuel şablonunuzu sözdizimi yaparken.

: Bu örnek kullanabilirsiniz http://plnkr.co/edit/a9OdMAq2YIwQFo7gixbj?p=preview etrafında poke


1
muhtemelen id = "xxx" i kaldırmalısınız, kimlik benzersiz olmalıdır, değil mi?
PeiSong Xiong

1
id kullanılabilir endeksi *ngFor="let control of checkboxGroup.controls['myValues'].controls ; let i=index""
Mirza

9
Bu harika, ancak tamamen genel bir onay kutusu dizisi oluşturur. Muhtemelen bir diziye veya başka bir şeye yükleniyor ve her onay kutusunu başka bir değerle ilişkilendiriyorsunuzdur. Örneğin, her form denetimine bir form etiketinde kullanmak üzere bir metin dizesini nasıl eklersiniz?
Askdesigners

NM Bunu harici bir dizinin
yanına henüz eşledim

@Askdesigners, onay kutularına ve etiketlere sahip olmak için çözümünüzü gönderebilir misiniz?
eddygeek

27

Onay kutusu bilgileri bir API'den eşzamansız olarak doldurulsa bile bunu Angular 6'da yapmak önceki sürümlere göre çok daha kolaydır.

Farkına varmamız gereken ilk şey, Angular 6'nın keyvalueborusu sayesinde FormArrayartık kullanmak zorunda olmadığımız ve bunun yerine a FormGroup.

İlk olarak, FormBuilder'ı kurucuya geçirin

constructor(
    private _formBuilder: FormBuilder,
) { }

Ardından formumuzu başlatın.

ngOnInit() {

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

}

Onay kutusu seçenekleri verilerimiz kullanılabilir olduğunda, onu yineleyin ve numaraya göre indekslenmiş arama dizilerine güvenmek zorunda kalmadan doğrudan FormGroupadlandırılmış olarak yuvaya yerleştirebiliriz FormControl.

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

Son olarak, şablonda yalnızca keyvalueonay kutularını yinelememiz gerekiyor : ek yok let index = ive onay kutuları otomatik olarak alfabetik sıraya göre olacak: çok daha temiz.

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

1
Basit bir kodlanmış onay kutusu değerleri dizisi durumunda da çok kullanışlıdır. Daha sonra benzer bir for döngüsü kullanarak form denetimlerini hemen ngOnInit () içinde ekleyebilirsiniz ve formunuzdaki onay kutuları, onay kutusu değerleri dizisini dinamik olarak yansıtacaktır
Arjan

3
Bu hala [key1 = true, key2 = false, key3 = true] 'yu alıntılıyor. ['Key1', '
key3

@ f.khantsis Bunu şu şekilde yapabilirsiniz: `const value = {key1: true, key2: false, key3: true}; const list = Object.entries (değer) .filter (([_, isSelected]) => isSelected) .map (([key]) => key); console.log (liste); `
zauni

2
En iyi çözüm imho. Görevlendirmeyi const checkboxes = ..foreach dışına yerleştirebilirsiniz;)
Bernoulli BT

Madde anahtarı, formdaki başka bir alanla aynı şeye eşitse ne olur? Örneğin, her biri "Küçük", "Orta" ve "Büyük" anahtarlarına sahip iki farklı onay kutusu dizim var.
Newclique

9

JSON biçiminde onay kutusu değerleri arıyorsanız

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

Tam örnek burada .

Sorudakiler yerine onay kutusu değerleri olarak Ülke Adlarını kullandığım için özür dilerim. Daha fazla açıklama -

Form için bir FormGroup oluşturun

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

Her onay kutusu, tek özelliği onay kutusunun değeri olan bir nesneden oluşturulmuş bir FormGroup olsun.

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

Onay kutuları için FormGroups dizisi, üst Formdaki 'ülkeler' için denetimi ayarlamak için kullanılır.

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

Şablonda, onay kutusu kontrolünün adını almak için bir kanal kullanın

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

7

Burada reaktif formları kullanarak soruyu tam olarak yanıtlayan bir çözüm göremiyorum, bu yüzden işte benim çözümüm.


Özet

İşte bir StackBlitz örneğiyle birlikte ayrıntılı açıklamanın özü.

  1. FormArrayOnay kutuları için kullanın ve formu başlatın.
  2. valueChangesGözlemlenebilir görüntüleme şey ama bileşeninde başka mağaza şeye formu istediğinizde için mükemmeldir. Harita true/ falseBurada istenen değerlere değerleri.
  3. falseGönderim sırasındaki değerleri filtreleyin .
  4. valueChangesGözlemlenebilir aboneliğinden çıkın.

StackBlitz örneği


Detaylı açıklama

Formu tanımlamak için FormArray kullanın

Doğru olarak işaretlenmiş cevapta daha önce belirtildiği gibi. FormArraybir dizideki verileri almayı tercih edeceğiniz bu tür durumlarda gitmenin yoludur. Yani yapmanız gereken ilk şey formu oluşturmaktır.

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

Bu, tüm onay kutularının başlangıç ​​değerini olarak ayarlayacaktır false.

Daha sonra, bu form değişkenlerini şablona kaydetmemiz ve şablonda görüntülemek için checkboxesdizi üzerinde yinelememiz gerekir ( FormArrayonay kutusu verileri DEĞİL ).

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

ValueChanges gözlemlenebilir kullanın

İşte burada verilen herhangi bir cevapta bahsetmediğim kısım. Bu gibi durumlarda, söz konusu verileri görüntülemek istediğimiz ancak başka bir şey olarak sakladığımız durumlarda, valueChangesgözlemlenebilir olan çok yararlıdır. Kullanarak valueChanges, içindeki checkboxesve sonra mapgelen true/ falsedeğerlerinden FormArrayistenen verilere olan değişiklikleri gözlemleyebiliriz . Onay kutusuna geçirilen herhangi bir gerçek değer onu işaretli olarak işaretleyeceğinden ve bunun tersi de geçerli olacağından , bunun onay kutularının seçimini değiştirmeyeceğini unutmayın .

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

Bu temelde FormArraydeğerleri orijinal checkboxesdiziye eşler ve valueonay kutusunun işaretlenmesi durumunda truedöndürür, aksi takdirde döndürür false. emitEvent: falseAyarı beri burada önemli olan FormArrayo neden olacaktır olmadan değerini valueChangessonsuz bir döngüye oluşturarak bir olayı yayacak şekilde. Ayarlayarak emitEventiçin false, biz emin yapıyoruz valueChangesbiz burada değerini ayarladığınızda yaymaz gözlemlenebilir.

Yanlış değerleri filtreleyin

İçindeki falsedeğerleri doğrudan filtreleyemeyiz FormArrayçünkü bunu yapmak, onay kutularına bağlı oldukları için şablonu bozar. Dolayısıyla mümkün olan en iyi çözüm, falsegönderim sırasında değerleri filtrelemektir . Bunu yapmak için yayma operatörünü kullanın.

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
}

Bu, temel olarak hatalı değerleri checkboxes.

ValueChanges aboneliğini iptal edin

Son olarak, aboneliğinizi iptal etmeyi unutmayın valueChanges

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

Not: Bir değerin içeri olarak ayarlanamadığı özel bir durum FormArrayvardır valueChanges, yani onay kutusu değeri sayı olarak ayarlanmışsa 0. Bu, onay kutusunun seçilemeyeceği gibi görünmesini sağlar, çünkü onay kutusu seçildiğinde FormControlnumara olarak 0(yanlış bir değer) ayarlanır ve bu nedenle işaretsiz kalır. Sayının 0bir değer olarak kullanılmaması tercih edilir, ancak gerekliyse, koşullu olarak 0doğru bir değere, örneğin dize '0'veya sadece düz bir değere ayarlamanız trueve sonra gönderdikten sonra tekrar sayıya dönüştürmeniz gerekir 0.

StackBlitz örneği

StackBlitz ayrıca, kullanıcı arayüzünde işaretli olarak işaretlenmeleri için varsayılan değerleri onay kutularına geçirmek istediğinizde kod içerir.


Bu hala iki diziyi korumayı ve onları senkronize tutmayı gerektirir. Hala umduğum kadar temiz değil. Belki de form kontrollerinin iki diziye sahip olmak yerine karmaşık değerleri tutmasını sağlayabiliriz.
MIWMIB

1
Değerin onay kutusu için doğru veya yanlış olması gerektiğinden karmaşık değer çalışmadı. Yani bu çözüm hala en iyi görünüyor.
MIWMIB

6

TL; DR

  1. Onay kutusu listesini doldurmak için FormGroup kullanmayı tercih ediyorum
  2. En az bir onay kutusunun seçildiğini kontrol etmek için özel bir doğrulayıcı yazın
  3. Çalışma örneği https://stackblitz.com/edit/angular-validate-at-least-one-checkbox-was-selected

Bu da bazen beni etkiledi, bu yüzden hem FormArray hem de FormGroup yaklaşımlarını denedim.

Çoğu zaman, onay kutusu listesi sunucuda dolduruldu ve bunu API aracılığıyla aldım. Ancak bazen önceden tanımlanmış değerinizle birlikte statik bir onay kutusu kümesine sahip olursunuz. Her kullanım senaryosunda, karşılık gelen FormArray veya FormGroup kullanılacaktır.

Temelde FormArraybir çeşididir FormGroup. Temel fark, verilerinin bir dizi olarak serileştirilmesidir (FormGroup durumunda bir nesne olarak serileştirilmesinin aksine). Bu, grup içinde dinamik formlar gibi kaç kontrolün bulunacağını bilmediğinizde özellikle yararlı olabilir.

Basitlik uğruna, basit bir ürün formunuz olduğunu hayal edin.

  • Gerekli bir ürün adı metin kutusu.
  • En az birinin kontrol edilmesi gereken bir kategori listesi. Listenin sunucudan alınacağını varsayın.

İlk olarak, sadece formControl ürün adı ile bir form oluşturdum. Zorunlu bir alandır.

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

Kategori dinamik olarak oluşturulduğundan, bu verileri daha sonra veriler hazır olduktan sonra forma eklemem gerekecek.

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

Kategori listesini oluşturmak için iki yaklaşım vardır.

1. Form Dizisi

  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>

Bu buildCategoryFormGroupbana bir FormArray döndürecektir. Ayrıca bağımsız değişken olarak seçilen değerin bir listesini alır, bu nedenle verileri düzenlemek için formu yeniden kullanmak isterseniz, bu yardımcı olabilir. Yeni bir ürün formu oluşturmak amacıyla henüz uygulanabilir değildir.

FormArray değerlerine erişmeye çalıştığınızda dikkat edin. Gibi görünecek [false, true, true]. Seçilen kimliğin bir listesini almak için, listeden kontrol etmek için biraz daha çalışma gerekiyordu, ancak dizi indeksine bağlıydı. Bana iyi gelmiyor ama işe yarıyor.

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

Bu yüzden FormGroupbu konuyu kullanarak geldim

2. Form Grubu

FormGroup'tan farklı olan, form verilerini bir anahtar ve bir form denetimi gerektiren nesne olarak depolamasıdır. Bu nedenle, anahtarı kategori kimliği olarak ayarlamak iyi bir fikirdir ve daha sonra onu geri alabiliriz.

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>

Form grubunun değeri şöyle görünecektir:

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

Ancak çoğu zaman yalnızca categoryIds listesini almak isteriz ["category2", "category3"]. Ayrıca bu verileri almak için bir get yazmam gerekiyor. FormArray ile karşılaştırıldığında bu yaklaşımı daha çok seviyorum, çünkü değeri aslında formun kendisinden alabilirim.

  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. En az bir onay kutusunu işaretlemek için özel doğrulayıcı seçildi

Doğrulayıcının en az X onay kutusunun seçili olduğunu kontrol etmesini sağladım, varsayılan olarak yalnızca bir onay kutusunu kontrol edecek.

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

4

Tıklandığında bir olay oluşturun ve ardından true değerini, onay kutusunun temsil ettiği adla manuel olarak değiştirin, ardından ad veya true aynı şekilde değerlendirilir ve doğru / yanlış listesi yerine tüm değerleri alabilirsiniz. Ör:

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

Bu, Angular Forms tarafından zaten true veya false olarak değiştirildikten sonra olayı yakalar, eğer doğruysa, adı onay kutusunun temsil ettiği adla değiştiririm; gerekirse, eğer gerekirse true / false olarak iyi.


Bu beni doğru yola getirdi, bunu yaptım this.customForm.patchValue ({[event.target.id]: event.target.checked});
Demodave

4

Açısal reaktif bir form kullanmak istiyorsanız ( https://angular.io/guide/reactive-forms ).

Onay kutuları grubunun çıktı değerini yönetmek için tek bir form denetimi kullanabilirsiniz.

bileşen

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

Kontrol listesi girişlerinin modelini / durumunu yönetir. Bu model, mevcut durumu ihtiyacınız olan değer formatına eşlemenize izin verir.

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 Form Kontrolü

Bu kontrol, kaydetmek istediği değeri örn.

değer çıktısı: "value_1,value_2"

Demoyu https://stackblitz.com/edit/angular-multi-checklist adresinde görün


Benim için kolayca en iyi çözüm. Çok teşekkür ederim.
Newclique

2

Benim çözümüm - Malzeme Görünümü ile Angular 5 için çözdüm
Bağlantı,

formArrayName = "bildirim"

(değiştir) = "updateChkbxArray (n.id, $ event.checked, 'bildirim')"

Bu şekilde, tek bir biçimde birden çok onay kutusu dizisi için çalışabilir. Her seferinde bağlanmak için kontrol dizisinin adını ayarlayın.

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>

Sonunda, formu kaydetmek / güncellemek için orijinal kayıt kimlikleri dizisi ile kaydetmeye başlayacaksınız. UI Görünümü

Formun json'unun ilgili kısmı

İyileştirme için herhangi bir açıklama yapmaktan mutluluk duyarız.


0

ŞABLON BÖLÜMÜ: -

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

KONTROLÖR BÖLÜMÜ: -

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

        }

1
Merhaba @EchoLogic .. Herhangi bir sorunuz olursa lütfen bana bildirin
Abhishek Srivastava

1
Bu, ReactiveForms'u değil, normal formları kullanıyor, bu yüzden soruyu cevaplamıyor
Guillaume

0

5 sentimi ekle) Soru modelim

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.