Angular ReactiveForms: Produire un tableau de valeurs de case à cocher?


104

Étant donné une liste de cases à cocher liées à la même chose formControlName, comment puis-je produire un tableau de valeurs de case à cocher liées au formControl, plutôt que simplement true/ false?

Exemple:

<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 produit actuellement:

true or false

Ce que je veux qu'il produise:

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

avez-vous trouvé une solution?
CP

C'est probablement le moyen le plus sophistiqué de créer des cases à cocher dans un formulaire. Ce n'est pas du tout simple.
mwilson

8
Angulaire. Tout ce que j'essaie de faire, c'est d'obtenir un mat-radio-group pour se lier sous ma forme réactive. Je ne me souviens pas avoir tant lutté avec angular. Tous les articles pointent vers la même chose. Je ne peux tout simplement pas le faire fonctionner. Tout le reste est très simple. Je le regarde probablement depuis trop longtemps. On a toujours l'impression que wayyyyy est trop complexe pour une valeur de tableau dans un formulaire.
mwilson

3
Oui , ce fut terrible quand j'ai demandé cela en 2016, et il est toujours terrible 2019.
ReactingToAngularVues

3
Je n'ajoute pas une tonne à cette question, mais je voulais que les autres sachent que je ressens la même chose. Cela seul a été la partie la plus difficile dans l'apprentissage des formes réactives angulaires. J'ai l'impression que ça ne devrait pas du tout être si difficile. Je suis heureux de voir que je ne suis pas seul dans la lutte. Merci d'avoir posé la question.
NorthStarCode

Réponses:


52

Avec l'aide de silentsod answer, j'ai écrit une solution pour obtenir des valeurs au lieu d'états dans mon formBuilder.

J'utilise une méthode pour ajouter ou supprimer des valeurs dans le formArray. C'est peut-être une mauvaise approche, mais ça marche!

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

Lorsque je soumets mon formulaire, par exemple mon modèle ressemble à:

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

Une seule chose manque, une fonction pour remplir le formArray si votre modèle a déjà des valeurs vérifiées.


comment vérifier si ma case est cochée lorsque je charge les données après avoir utilisé votre exemple pour entrer dans db?
Devora

Dans cette solution, le formulaire est toujours valide même si la case n'est pas cochée
Teja

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

48

Voici un bon endroit pour utiliser FormArray https://angular.io/docs/ts/latest/api/forms/index/FormArray-class.html

Pour commencer, nous allons construire notre gamme de contrôles avec ou avec un FormBuildernouveauFormArray

FormBuilder

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

nouveau FormArray

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

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

Assez facile à faire, mais nous allons ensuite changer notre modèle et laisser le moteur de création de modèles gérer la façon dont nous nous lions à nos contrôles:

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>

Ici, nous itérons sur notre ensemble de FormControlsdans notre myValues FormArrayet pour chaque contrôle, nous nous lions [formControl]à ce contrôle plutôt qu'au FormArraycontrôle et <div>{{checkboxGroup.controls['myValues'].value}}</div>produit true,false,truetout en rendant la syntaxe de votre modèle un peu moins manuelle.

Vous pouvez utiliser cet exemple: http://plnkr.co/edit/a9OdMAq2YIwQFo7gixbj?p=preview pour fouiller


1
vous devriez probablement supprimer id = "xxx", l'identifiant doit être unique, non?
PeiSong Xiong

1
for id pourrait être utilisé index *ngFor="let control of checkboxGroup.controls['myValues'].controls ; let i=index""
Mirza

9
C'est cool, mais produit un tableau complètement générique de cases à cocher. Vous allez probablement charger dans un tableau ou autre chose, et associer chaque case à cocher à une autre valeur. Comment ajouter, par exemple, une chaîne de texte à utiliser dans une étiquette de formulaire à chaque contrôle de formulaire?
Askdesigners

NM Je viens de le mapper à côté d'un tableau externe: p
Askdesigners

@Askdesigners pouvez-vous poster votre solution pour avoir les cases à cocher et les étiquettes?
eddygeek

25

Il est beaucoup plus facile de le faire dans Angular 6 que dans les versions précédentes, même lorsque les informations de case à cocher sont remplies de manière asynchrone à partir d'une API.

La première chose à réaliser est que grâce au keyvaluetube d' Angular 6, nous n'avons plus besoin d'utiliser FormArray, et pouvons à la place imbriquer un FormGroup.

Tout d'abord, passez FormBuilder dans le constructeur

constructor(
    private _formBuilder: FormBuilder,
) { }

Ensuite, initialisez notre formulaire.

ngOnInit() {

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

}

Lorsque nos données d'options de case à cocher sont disponibles, itérez-les et nous pouvons les pousser directement dans l'imbriqué en FormGrouptant que nommé FormControl, sans avoir à compter sur des tableaux de recherche indexés par nombre.

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

Enfin, dans le modèle, nous avons juste besoin d'itérer les keyvaluecases à cocher: pas de supplément let index = i, et les cases à cocher seront automatiquement dans l'ordre alphabétique: beaucoup plus propre.

<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
Très utilisable également dans le cas d'un simple tableau codé en dur de valeurs de case à cocher. Ensuite, vous pouvez ajouter les contrôles de formulaire en utilisant une boucle for similaire tout de suite dans ngOnInit (), et les cases à cocher de votre formulaire refléteront dynamiquement le tableau des valeurs de case à cocher
Arjan

3
Cela extrait encore [key1 = true, key2 = false, key3 = true]. Nous voulons ['key1', 'key3']
f.khantsis

@ f.khantsis Vous pouvez le faire comme ça: `const value = {key1: true, key2: false, key3: true}; const list = Object.entries (valeur) .filter (([_, isSelected]) => isSelected) .map (([key]) => key); console.log (liste); `
zauni

1
Meilleure solution à mon humble avis. Vous pouvez placer l'attribution de l' const checkboxes = ..extérieur du foreach;)
Bernoulli IT

Que se passe-t-il lorsque la clé d'élément équivaut à la même chose qu'un autre champ du formulaire? Par exemple, j'ai deux tableaux de cases à cocher différents, chacun avec les clés «Small», «Medium» et «Large»?
Newclique

9

Si vous recherchez des valeurs de case à cocher au format JSON

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

Exemple complet ici .

Je m'excuse d'utiliser les noms de pays comme valeurs de case à cocher au lieu de ceux de la question. Explication supplémentaire -

Créer un FormGroup pour le formulaire

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

Laissez chaque case à cocher être un FormGroup construit à partir d'un objet dont la seule propriété est la valeur de la case à cocher.

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

Le tableau de FormGroups pour les cases à cocher est utilisé pour définir le contrôle pour les «pays» dans le formulaire parent.

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

Dans le modèle, utilisez un tube pour obtenir le nom du contrôle de case à cocher

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

6

TL; DR

  1. Je préfère utiliser FormGroup pour remplir la liste des cases à cocher
  2. Ecrire un validateur personnalisé pour vérifier qu'au moins une case a été cochée
  3. Exemple de travail https://stackblitz.com/edit/angular-validate-at-least-one-checkbox-was-selected

Cela m'a également frappé parfois, alors j'ai essayé les approches FormArray et FormGroup.

La plupart du temps, la liste des cases à cocher était remplie sur le serveur et je l'ai reçue via l'API. Mais parfois, vous aurez un ensemble statique de cases à cocher avec votre valeur prédéfinie. Avec chaque cas d'utilisation, le FormArray ou FormGroup correspondant sera utilisé.

Fondamentalement, FormArrayest une variante de FormGroup. La principale différence est que ses données sont sérialisées en tant que tableau (par opposition à être sérialisées en tant qu'objet dans le cas de FormGroup). Cela peut être particulièrement utile lorsque vous ne savez pas combien de contrôles seront présents dans le groupe, comme les formulaires dynamiques.

Par souci de simplicité, imaginez que vous disposez d'un formulaire de création de produit simple avec

  • Une zone de texte de nom de produit obligatoire.
  • Une liste de catégories à sélectionner, dont au moins une doit être vérifiée. Supposons que la liste sera extraite du serveur.

Tout d'abord, j'ai mis en place un formulaire avec uniquement le nom de produit formControl. C'est un champ obligatoire.

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

Étant donné que la catégorie est rendue dynamiquement, je devrai ajouter ces données dans le formulaire plus tard, une fois les données prêtes.

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

Il existe deux approches pour constituer la liste des catégories.

1. Form 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>

Cela buildCategoryFormGroupme renverra un FormArray. Il prend également une liste de valeurs sélectionnées comme argument, donc si vous souhaitez réutiliser le formulaire pour modifier les données, cela peut être utile. Dans le but de créer un nouveau formulaire de produit, il n'est pas encore applicable.

A noté que lorsque vous essayez d'accéder aux valeurs formArray. Cela ressemblera à [false, true, true]. Pour obtenir une liste des identifiants sélectionnés, il a fallu un peu plus de travail pour vérifier dans la liste, mais en fonction de l'index du tableau. Cela ne me semble pas bon mais ça marche.

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

C'est pourquoi je suis venu utiliser FormGrouppour cette question

2. Groupe de formulaires

La différence du formGroup est qu'il stockera les données du formulaire en tant qu'objet, ce qui nécessitait une clé et un contrôle de formulaire. C'est donc la bonne idée de définir la clé comme categoryId, puis nous pourrons la récupérer plus tard.

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>

La valeur du groupe de formulaires ressemblera à ceci:

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

Mais le plus souvent, nous voulons obtenir uniquement la liste des ID de catégorie ["category2", "category3"]. Je dois aussi écrire un get pour prendre ces données. J'aime mieux cette approche par rapport à formArray, car je pourrais en fait prendre la valeur du formulaire lui-même.

  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. Un validateur personnalisé pour cocher au moins une case a été coché

J'ai fait en sorte que le validateur vérifie qu'au moins X case à cocher était cochée, par défaut, il ne vérifiera qu'une seule case.

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

6

Je ne vois pas de solution ici qui réponde complètement à la question en utilisant des formes réactives dans toute son étendue, alors voici ma solution pour la même chose.


Résumé

Voici l'essentiel de l'explication détaillée avec un exemple StackBlitz.

  1. Utilisez FormArraypour les cases à cocher et initialisez le formulaire.
  2. L' valueChangesobservable est parfait lorsque vous voulez que le formulaire affiche quelque chose mais stocke autre chose dans le composant. Mappez ici les valeurs true/ aux falsevaleurs souhaitées.
  3. Filtrez les falsevaleurs au moment de la soumission.
  4. Désabonnez-vous d' valueChangesobservable.

Exemple de StackBlitz


Explication détaillée

Utilisez FormArray pour définir le formulaire

Comme déjà mentionné dans la réponse marquée comme correcte. FormArrayest la voie à suivre dans les cas où vous préférez obtenir les données dans un tableau. La première chose à faire est donc de créer le formulaire.

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

Cela définira simplement la valeur initiale de toutes les cases à cocher false.

Ensuite, nous devons enregistrer ces variables de formulaire dans le modèle et parcourir le checkboxestableau (PAS les FormArraydonnées mais les cases à cocher) pour les afficher dans le modèle.

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

Utiliser l'observable valueChanges

Voici la partie que je ne vois pas mentionnée dans aucune réponse donnée ici. Dans des situations comme celle-ci, où nous aimerions afficher lesdites données mais les stocker comme autre chose, l' valueChangesobservable est très utile. En utilisant valueChanges, nous pouvons observer les changements dans checkboxes, puis maples valeurs true/ falsereçues de la FormArrayaux données souhaitées. Notez que cela ne modifiera pas la sélection des cases à cocher car toute valeur de vérité passée à la case à cocher la marquera comme cochée et vice-versa.

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

Cela mappe essentiellement les FormArrayvaleurs sur le checkboxestableau d' origine et renvoie le valuedans le cas où la case à cocher est cochée true, sinon elle retourne false. Le emitEvent: falseest important ici car la définition de la FormArrayvaleur sans elle entraînera l'émission valueChangesd'un événement créant une boucle sans fin. En définissant emitEventsur false, nous nous assurons que l' valueChangesobservable n'émet pas lorsque nous définissons la valeur ici.

Filtrer les fausses valeurs

Nous ne pouvons pas filtrer directement les falsevaleurs dans le FormArraycar cela gâcherait le modèle car elles sont liées aux cases à cocher. La meilleure solution possible est donc de filtrer les falsevaleurs lors de la soumission. Utilisez l'opérateur de diffusion pour ce faire.

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
}

Cela filtre essentiellement les fausses valeurs du fichiercheckboxes .

Se désabonner de valueChanges

Enfin, n'oubliez pas de vous désabonner de valueChanges

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

Remarque: il existe un cas particulier où une valeur ne peut pas être définie sur FormArrayin valueChanges, c'est-à-dire si la valeur de la case à cocher est définie sur le nombre 0. Cela donnera l'impression que la case à cocher ne peut pas être cochée car la sélection de la case à cocher définira le FormControlcomme numéro 0(une valeur erronée) et la gardera donc décochée. Il serait préférable de ne pas utiliser le nombre 0comme valeur, mais si cela est nécessaire, vous devez conditionnellement définir 0une valeur de vérité, par exemple une chaîne '0'ou simplement, truepuis lors de la soumission, le reconvertir en nombre 0.

Exemple de StackBlitz

Le StackBlitz a également un code lorsque vous souhaitez transmettre des valeurs par défaut aux cases à cocher afin qu'elles soient marquées comme cochées dans l'interface utilisateur.


4

Créez un événement lorsque vous cliquez dessus, puis remplacez manuellement la valeur de true par le nom de ce que la case à cocher représente, puis le nom ou true évaluera la même chose et vous pourrez obtenir toutes les valeurs au lieu d'une liste de 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
    }
}

Cela intercepte l'événement après qu'il a déjà été changé en vrai ou faux par Angular Forms, si c'est vrai, je change le nom en nom de ce que la case à cocher représente, qui si nécessaire évaluera également à vrai si elle est vérifiée pour vrai / faux comme bien.


Cela m'a mis sur la bonne voie, j'ai fini par faire this.customForm.patchValue ({[event.target.id]: event.target.checked});
Demodave

4

Si vous souhaitez utiliser un formulaire réactif angulaire ( https://angular.io/guide/reactive-forms ).

Vous pouvez utiliser un contrôle de formulaire pour gérer la valeur sortie du groupe de cases à cocher.

composant

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

Gère le modèle / l'état des entrées de la liste de contrôle. Ce modèle vous permet de mapper l'état actuel sur le format de valeur dont vous avez besoin.

Modèle:

{
   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 Contrôle de formulaire

Ce contrôle stocke la valeur que vous souhaitez enregistrer comme par exemple

sortie de valeur: "value_1,value_2"

Voir la démo sur https://stackblitz.com/edit/angular-multi-checklist


Facilement la meilleure solution pour moi. Merci beaucoup.
Newclique

2

Ma solution - résolu le problème pour Angular 5 avec Material View
La connexion se fait via le

formArrayName = "notification"

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

De cette façon, il peut fonctionner pour plusieurs tableaux de cases à cocher dans un seul formulaire. Définissez simplement le nom du tableau de contrôles à connecter à chaque fois.

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>

À la fin, vous enregistrez le formulaire avec un tableau d'ID d'enregistrement d'origine à enregistrer / mettre à jour. La vue de l'interface utilisateur

La partie relevat du json du formulaire

Sera heureux d'avoir des remarques d'amélioration.


0

PARTIE DU MODÈLE: -

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

PARTIE CONTRÔLEUR: -

        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
Salut @EchoLogic .. S'il vous plaît laissez-moi savoir en cas de question
Abhishek Srivastava

1
Cela n'utilise pas ReactiveForms mais des formes régulières donc ne répond pas à la question
Guillaume

0

Ajouter mes 5 cents) Mon modèle de question

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.