Angular ReactiveForms: ¿Produciendo una matriz de valores de casilla de verificación?


104

Dada una lista de casillas de verificación vinculadas a lo mismo formControlName, ¿cómo puedo producir una matriz de valores de casilla de verificación vinculados al formControl, en lugar de simplementetrue / false?

Ejemplo:

<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 actualmente produce:

true or false

Lo que quiero que produzca:

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

encontraste alguna solución?
CP

Esta es probablemente la forma más sobredimensionada de hacer casillas de verificación en un formulario. Esto no es nada sencillo.
mwilson

8
Angular. Todo lo que estoy tratando de hacer es que un grupo de radio-tapete se una en mi forma reactiva. No recuerdo haber luchado tanto con angular. Todos los artículos apuntan a lo mismo. Simplemente no puedo hacer que funcione. Todo lo demás es muy sencillo. Probablemente lo he estado mirando demasiado tiempo. Todavía se siente como muchísima complejidad para un valor de matriz en un formulario.
mwilson

3
Sí, fue terrible cuando pregunté esto en 2016, y todavía es terrible en 2019.
ReactingToAngularVues

3
No estoy agregando mucho a esta pregunta, pero quería que los demás supieran que siento lo mismo. Esto solo ha sido la parte más difícil en el aprendizaje de formas reactivas angulares. Siento que no debería ser tan difícil, en absoluto. Sin embargo, estoy feliz de ver que no estoy solo en la lucha. Así que gracias por publicar la pregunta.
NorthStarCode

Respuestas:


52

Con la ayuda de silenntsod answer, escribí una solución para obtener valores en lugar de estados en mi formBuilder.

Utilizo un método para agregar o eliminar valores en formArray. Puede que sea un mal enfoque, ¡pero funciona!

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

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

Cuando envío mi formulario, por ejemplo, mi modelo se ve así:

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

Solo falta una cosa, una función para completar el formArray si su modelo ya tiene valores comprobados.


¿Cómo verifico si mi casilla de verificación está marcada cuando cargo los datos después de usar su ejemplo para ingresar a la base de datos?
Devora

En esta solución, el formulario siempre es válido incluso si la casilla de verificación no está seleccionada
Teja

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

48

Este es un buen lugar para usar FormArray https://angular.io/docs/ts/latest/api/forms/index/FormArray-class.html

Para empezar, FormBuildercrearemos nuestro conjunto de controles con un o con un nuevoFormArray

FormBuilder

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

nuevo FormArray

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

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

Es bastante fácil de hacer, pero luego cambiaremos nuestra plantilla y dejaremos que el motor de plantillas maneje cómo nos vinculamos a nuestros controles:

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>

Aquí estamos iterando sobre nuestro conjunto de FormControlsen nuestro myValues FormArrayy para cada control estamos vinculando [formControl]a ese control en lugar de al FormArraycontrol y <div>{{checkboxGroup.controls['myValues'].value}}</div>produce true,false,trueal mismo tiempo que hacemos que la sintaxis de la plantilla sea un poco menos manual.

Puede usar este ejemplo: http://plnkr.co/edit/a9OdMAq2YIwQFo7gixbj?p=preview para hurgar


1
probablemente debería eliminar id = "xxx", la identificación debe ser única, ¿verdad?
PeiSong Xiong

1
para la identificación podría usarse índice *ngFor="let control of checkboxGroup.controls['myValues'].controls ; let i=index""
Mirza

9
Esto es genial, pero produce una serie de casillas de verificación completamente genérica. Presumiblemente, estaría cargando una matriz o algo más, y asociando cada casilla de verificación con algún otro valor. ¿Cómo agrega, por ejemplo, una cadena de texto para usar en una etiqueta de formulario a cada control de formulario?
Askdesigners

NM Acabo de mapearlo junto a una matriz externa: p
Askdesigners

@Askdesigners ¿pueden publicar su solución para tener las casillas de verificación y las etiquetas?
eddygeek

25

Es significativamente más fácil hacer esto en Angular 6 que en versiones anteriores, incluso cuando la información de la casilla de verificación se completa de forma asincrónica desde una API.

Lo primero que debemos darnos cuenta es que, gracias a la keyvaluetubería de Angular 6, ya no necesitamos usar FormArraymás, y en su lugar podemos anidar unFormGroup .

Primero, pase FormBuilder al constructor

constructor(
    private _formBuilder: FormBuilder,
) { }

Luego inicialice nuestro formulario.

ngOnInit() {

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

}

Cuando nuestros datos de opciones de casilla de verificación están disponibles, iterarlos y podemos enviarlos directamente al anidado FormGroupcomo un nombre FormControl, sin tener que depender de matrices de búsqueda indexadas por número.

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

Finalmente, en la plantilla solo necesitamos iterar la keyvaluede las casillas de verificación: no adicional let index = i, y las casillas de verificación estarán automáticamente en orden alfabético: mucho más limpio.

<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
Muy útil también en el caso de una matriz codificada simple de valores de casilla de verificación. Luego puede agregar los controles de formulario usando un bucle for similar de inmediato en ngOnInit (), y las casillas de verificación en su formulario reflejarán dinámicamente la matriz de valores de casilla de verificación
Arjan

3
Esto sigue siendo extractos [key1 = true, key2 = false, key3 = true]. Queremos ['key1', 'key3']
f.khantsis

@ f.khantsis Puedes hacerlo así: `const value = {key1: true, key2: false, key3: true}; lista constante = Object.entries (valor) .filter (([_, isSelected]) => isSelected) .map (([key]) => key); console.log (lista); `
zauni

1
La mejor solución en mi humilde opinión. Puede colocar la asignación de const checkboxes = ..fuera del foreach;)
Bernoulli IT

¿Qué sucede cuando la clave del elemento es igual a otro campo del formulario? Por ejemplo, tengo dos matrices de casillas de verificación diferentes, cada una con las teclas 'Pequeño', 'Medio' y 'Grande'.
Newclique

9

Si está buscando valores de casilla de verificación en formato JSON

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

Ejemplo completo aquí .

Pido disculpas por usar nombres de países como valores de casilla de verificación en lugar de los de la pregunta. Explicación adicional -

Crea un FormGroup para el formulario

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

Deje que cada casilla de verificación sea un FormGroup construido a partir de un objeto cuya única propiedad es el valor de la casilla de verificación.

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

La matriz de FormGroups para las casillas de verificación se utiliza para establecer el control de los 'países' en el formulario principal.

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

En la plantilla, use una tubería para obtener el nombre del control de casilla de verificació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>

6

TL; DR

  1. Prefiero usar FormGroup para completar la lista de casillas de verificación
  2. Escriba un validador personalizado para comprobar que se seleccionó al menos una casilla de verificación
  3. Ejemplo de trabajo https://stackblitz.com/edit/angular-validate-at-least-one-checkbox-was-selected

Esto también me sorprendió a veces, así que probé los enfoques FormArray y FormGroup.

La mayoría de las veces, la lista de casillas de verificación se completó en el servidor y la recibí a través de API. Pero a veces tendrá un conjunto estático de casillas de verificación con su valor predefinido. Con cada caso de uso, se utilizará el FormArray o FormGroup correspondiente.

Básicamente FormArrayes una variante de FormGroup. La diferencia clave es que sus datos se serializan como una matriz (en lugar de ser serializados como un objeto en el caso de FormGroup). Esto puede ser especialmente útil cuando no sabe cuántos controles estarán presentes dentro del grupo, como formularios dinámicos.

En aras de la simplicidad, imagine que tiene un formulario de creación de producto simple con

  • Un cuadro de texto de nombre de producto obligatorio.
  • Una lista de categorías para seleccionar, requiere al menos una para ser marcada. Suponga que la lista se recuperará del servidor.

Primero, configuré un formulario con solo el nombre del producto formControl. Es un campo obligatorio.

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

Dado que la categoría se está procesando dinámicamente, tendré que agregar estos datos al formulario más tarde, una vez que los datos estén listos.

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

Hay dos enfoques para crear la lista de categorías.

1. Matriz de formas

  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>

Esto buildCategoryFormGroupme devolverá un FormArray. También toma una lista de valores seleccionados como argumento, por lo que si desea reutilizar el formulario para editar datos, podría ser útil. Para el propósito de crear un nuevo formulario de producto, aún no es aplicable.

Observó que cuando intenta acceder a los valores de formArray. Se verá así [false, true, true]. Para obtener una lista de ID seleccionados, se requirió un poco más de trabajo para verificar de la lista, pero según el índice de la matriz. No me suena bien, pero funciona.

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

Por eso se me ocurrió usar FormGrouppara el caso

2. Formar grupo

La diferencia de formGroup es que almacenará los datos del formulario como el objeto, que requiere una clave y un control de formulario. Por lo tanto, es una buena idea establecer la clave como categoryId y luego podemos recuperarla más tarde.

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>

El valor del grupo de formularios se verá así:

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

Pero la mayoría de las veces queremos obtener solo la lista de categoryIds como ["category2", "category3"]. También tengo que escribir un get para tomar estos datos. Me gusta más este enfoque en comparación con formArray, porque en realidad podría tomar el valor del formulario en sí.

  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. Se seleccionó un validador personalizado para marcar al menos una casilla de verificación

Hice que el validador marcara al menos X la casilla de verificación seleccionada, de forma predeterminada, solo se verificará con una casilla de verificación.

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

No veo una solución aquí que responda completamente a la pregunta utilizando formas reactivas en su máxima extensión, así que aquí está mi solución para lo mismo.


Resumen

Aquí está la esencia de la explicación detallada junto con un ejemplo de StackBlitz.

  1. Utilice FormArraypara las casillas de verificación e inicialice el formulario.
  2. El valueChangesobservable es perfecto para cuando desea que el formulario muestre algo pero almacene algo más en el componente. Mapear el true/false valores a los valores deseados aquí.
  3. Filtrar el false valores en el momento del envío.
  4. Darse de baja de valueChangesobservable.

Ejemplo de StackBlitz


Explicación detallada

Utilice FormArray para definir el formulario

Como ya se mencionó en la respuesta marcada como correcta. FormArrayes el camino a seguir en los casos en los que preferiría obtener los datos en una matriz. Entonces, lo primero que debe hacer es crear el formulario.

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

Esto solo establecerá el valor inicial de todas las casillas de verificación en false.

A continuación, necesitamos registrar estas variables de formulario en la plantilla e iterar sobre la checkboxesmatriz (NO los FormArraydatos de la casilla de verificación) para mostrarlos en la plantilla.

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

Hacer uso de los cambios de valor observables

Aquí está la parte que no veo mencionada en ninguna respuesta dada aquí. En situaciones como esta, donde nos gustaría mostrar dichos datos pero almacenarlos como otra cosa, el valueChangesobservable es muy útil. UtilizandovalueChanges , podemos observar los cambios en checkboxesy luego maplos valores true/ falserecibidos de los FormArraydatos deseados. Tenga en cuenta que esto no cambiará la selección de las casillas de verificación, ya que cualquier valor verdadero que se pase a la casilla de verificación lo marcará como marcado y viceversa.

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

Esto básicamente asigna los FormArrayvalores a la checkboxesmatriz original y devuelve elvalue en caso de que la casilla de verificación esté marcada como true, de lo contrario, regresa false. El emitEvent: falsees importante aquí, ya establecer el FormArrayvalor sin que hará que valueChangespara emitir un evento creando un bucle sin fin. Al establecer emitEventen false, nos aseguramos de que el valueChangesobservable no se emita cuando establecemos el valor aquí.

Filtra los valores falsos

No podemos filtrar directamente los falsevalores en el FormArrayporque hacerlo estropearía la plantilla, ya que están vinculados a las casillas de verificación. Entonces, la mejor solución posible es filtrar los falsevalores durante el envío. Utilice el operador de propagación para hacer esto.

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
}

Esto básicamente filtra los valores falsos de checkboxes.

Darse de baja de valueChanges

Por último, no olvide darse de baja de valueChanges

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

Nota: Hay un caso especial en el que un valor no se puede ajustar a la FormArrayde valueChanges, por ejemplo, si el valor de la casilla de verificación se establece en el número 0. Esto hará que parezca que la casilla de verificación no se puede seleccionar, ya que al seleccionar la casilla de verificación se establecerá FormControlel número 0(un valor falso) y, por lo tanto, se mantendrá sin marcar. Sería preferible no usar el número 0como un valor, pero si es necesario, debe establecer condicionalmente 0un valor verdadero, digamos cadena '0'o simplemente simple truey luego, al enviarlo, convertirlo de nuevo al número 0.

Ejemplo de StackBlitz

StackBlitz también tiene código para cuando desea pasar valores predeterminados a las casillas de verificación para que se marquen como marcadas en la interfaz de usuario.


4

Haga un evento cuando se haga clic y luego cambie manualmente el valor de verdadero por el nombre de lo que representa la casilla de verificación, luego el nombre o verdadero evaluará lo mismo y podrá obtener todos los valores en lugar de una lista de verdadero / falso. Ex:

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

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

Esto detecta el evento después de que Angular Forms ya lo cambió a verdadero o falso, si es cierto, cambio el nombre al nombre de lo que representa la casilla de verificación, que si es necesario, también se evaluará como verdadero si se verifica verdadero / falso como bien.


Esto me puso en el camino correcto, terminé haciendo esto this.customForm.patchValue ({[event.target.id]: event.target.checked});
Demodave

4

Si desea utilizar una forma reactiva angular ( https://angular.io/guide/reactive-forms ).

Puede usar un control de formulario para administrar el valor de salida del grupo de casillas de verificación.

componente

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

Gestiona el modelo / estado de las entradas de la lista de verificación. Este modelo le permite asignar el estado actual a cualquier formato de valor que necesite.

Modelo:

{
   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 Control de formulario

Este control almacena el valor que le gustaría guardar como, por ejemplo,

salida de valor: "value_1,value_2"

Vea la demostración en https://stackblitz.com/edit/angular-multi-checklist


Fácilmente la mejor solución para mí. Muchas gracias.
Newclique

2

Mi solución: lo resolví para Angular 5 con Vista de material
La conexión es a través de

formArrayName = "notificación"

(cambio) = "updateChkbxArray (n.id, $ event.checked, 'notificación')"

De esta manera, puede funcionar para múltiples matrices de casillas de verificación en una forma. Simplemente configure el nombre de la matriz de controles para conectarse cada vez.

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>

Al final, podrá guardar el formulario con una matriz de ID de registros originales para guardar / actualizar. La vista de la interfaz de usuario

La parte relevat del json de la forma

Estará encantado de tener algún comentario para mejorar.


0

PARTE DE LA PLANTILLA: -

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

PARTE DEL CONTROLADOR: -

        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
Hola @EchoLogic .. Por favor, avíseme en caso de cualquier consulta
Abhishek Srivastava

1
Esto no usa ReactiveForms sino formularios regulares, por lo que no responde a la pregunta
Guillaume

0

Agregue mis 5 centavos) Mi modelo de pregunta

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

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.