EDITAR 1:

Modifico mi pregunta para aclarar mi necesidad.

Tengo un FormGroup que contiene FormControl.

Entre estos FormControl, hay uno que recibe una matriz de valores.

Lo que estoy buscando es si hay una solución para hacer que el FormControl que recibe los valores de una matriz en su lugar reciba valores en un valor de cadena separado por comas (sin los corchetes []).

Lo que obtengo: (Array Values)

Array Values

Lo que quiero: (valores de cadena separados por comas sin brackets[])

enter image description here

Enlace de la bifurcación: aquí

  • Gracias de antemano por su ayuda

Pregunta original:

Me gustaría convertir los datos recibidos de un FormArray a cadenas con comas.

Logré hacer esto en Console.log, pero no sé cómo enviar los datos convertidos al FormGroup.

Mi archivo TS:

  accessoire: string;
  this.demandeDevis = this.formBuilder.group({
    accessoires: new FormArray([]),
    accessoire: this.accessoire,
  });

  onCheckboxChange(event) {
    const checkAcs: FormArray = this.demandeDevis.get(
      'accessoires'
    ) as FormArray;
    
    if (event.target.checked) {
      checkAcs.push(new FormControl(event.target.value));
      console.log(checkAcs.value.toString());
      this.accessoire = checkAcs.value.toString();
    } else {
      let i: number = 0;
      checkAcs.controls.forEach((item: FormControl) => {
        if (item.value == event.target.value) {
          checkAcs.removeAt(i);
              return;
        }
        i++;
      });
    }
  }

Mi HTML:

  <ul class="list-group list-group-flush">
    <li class="list-group-item p-3">
      Ventilateur cabine
      <label class="switch">
        <input type="checkbox" value="Ventilateur cabine" class="primary"
          (change)="onCheckboxChange($event)" />
        <span class="slider"></span>
      </label>
    </li>
    <li class="list-group-item p-3">
      Manoeuvre pompier
      <label class="switch">
        <input type="checkbox" class="primary" value="Manoeuvre pompier"
          (change)="onCheckboxChange($event)" />
        <span class="slider"></span>
      </label>
    </li>
    <li class="list-group-item p-3">
      Afficheur à tous les étages
      <label class="switch">
        <input type="checkbox" class="primary" value="Afficheur à tous les étages"
         (change)="onCheckboxChange($event)" />
        <span class="slider"></span>
      </label>
    </li>
    <li class="list-group-item p-3">
      Gong
      <label class="switch">
        <input type="checkbox" class="primary" value="Gong"
          (change)="onCheckboxChange($event)" />
          <span class="slider"></span>
      </label>
    </li>
    <li class="list-group-item p-3">
      Système de secours automatique
      <label class="switch">
        <input type="checkbox" class="primary" value="Système de secours automatique"
           (change)="onCheckboxChange($event)" />
        <span class="slider"></span>
      </label>
    </li>
  </ul>

Cuando sigo estos pasos, obtengo null en "Accessoire" y valores de matriz en "Accessoires".

Lo que estoy buscando es tomar los valores elegidos de una lista de casillas de verificación y convertirlos en cadenas con comas. No quiero enviarlos en forma de matrices.

Gracias de antemano por sus soluciones.

EDITAR 1:

Usé la primera opción de la solución @akash y está funcionando. Solo tengo un pequeño problema. Cuando obtengo los valores seleccionados en un input, y quiero enviarlo a un formControl ... obtengo el formulario de matriz con corchetes ... Lo que quiero es un formulario de cadena con comas. aquí está el enlace de mi problema: https://stackblitz.com/edit/reactive-form-string-values

3
TheScripterX 7 oct. 2020 a las 12:27

5 respuestas

La mejor respuesta
<mat-select 
      [value]="toppings.value?toppings?.value.split(','):null" 
      (selectionChange)="toppings.setValue($event.value.join(','))"
       multiple>
...
</mat-select>

Recuerde que existe un FormControl incluso si no tiene entrada. Bueno, necesita reescribir todo su código para recibir una cadena, algunos como este stackblitz bifurcado

4
Luis Limas 13 oct. 2020 a las 15:29

Actualización 2 :

Para completar su formulario a partir de valores de base de datos, simplemente inicialice el control toppings como se muestra a continuación (consulte esta bifurcación) -

toppingsValue: string = 'Extra cheese, Mushroom';
this.demandeDevis = this.formBuilder.group({
      toppings: [this.toppingsValue.split(',').map(a => a.trim())]
});

Actualización 1 :

Creo que entendí mal lo que estás tratando de lograr. Comprenda cómo funciona el FormGroup angular. FormGroup tiene un campo de controles que es lo que pasa como un objeto a continuación. Este objeto es una clave-valor donde clave es su nombre de control (ingredientes) y el valor es su control (por ejemplo, FormControl, FormArray o FormGroup) -

this.demandeDevis = this.formBuilder.group({
      toppings: this.toppings 
});

Entonces, cuando haces this.demandeDevis.value, obtienes el objeto con las mismas claves (ingredientes) y valores en el control correspondiente. Puede utilizar el siguiente código para obtener los valores separados por comas para toppings. No estoy seguro si esto es lo que está buscando porque es obvio (consulte esta bifurcación) -

validateForm(){
    const toppingsValue = this.demandeDevis.controls['toppings'].value;
    console.log(toppingsValue.toString()); 
}

Respuesta original :

Si está abierto a diferentes formas de cómo le gustaría que se vea su IU, use angular material

Opción 1 :

Utilice el componente mat-select. Con el siguiente ejemplo, no necesita manejar la selección / deselección de opciones. Consulta este ejemplo en StackBlitz. -

<mat-form-field appearance="fill">
  <mat-label>Toppings</mat-label>
  <mat-select [formControl]="toppings" multiple>
    <mat-option *ngFor="let topping of toppingList" [value]="topping">{{topping}}</mat-option>
  </mat-select>
</mat-form-field>

<div>
{{toppings.value}}
</div>

Opción 2 :

Si no desea utilizar el menú desplegable, utilice mat-selection-list, consulte este ejemplo. El siguiente ejemplo utiliza una referencia a mat-selection-list para obtener la lista de opciones seleccionadas en el componente:

<mat-selection-list #shoes (selectionChange)=selectionChange()>
  <mat-list-option [value]="shoe" *ngFor="let shoe of typesOfShoes">
    {{shoe}}
  </mat-list-option>
</mat-selection-list>
{{selectedValuesG}}
3
Luis Limas 12 oct. 2020 a las 21:42

Puede hacer algo como esto aquí

 ngOnInit() {
  this.initDemandeDevis();
  this.toppings.valueChanges.subscribe(value => {
    this.demandeDevis.patchValue({
      toppingsToString: value.length > 0 ? value.join(",") : ""
    });
  });
 }

 initDemandeDevis() {
   this.demandeDevis = this.formBuilder.group({
     toppingsToString: "",
     accessoires: null
   });
 }

Tendrá que volver a dividirlo para completar la matriz de ingredientes, pero no estoy seguro de si lo necesita.

2
mr.vea 14 oct. 2020 a las 20:43

Mi solución será usar Observable y transformar los datos cuando sea necesario.

// We define an Observable list of toppings
allToppings$: Observable<string[]> = of (['Extra cheese', 'Mushroom', 'Onion', 'Pepperoni', 'Sausage', 'Tomato']);

// We define our FormGroup
demandeDevis: FormGroup = this.formBuilder.group({
  toppings: [[]]
});

// Lets assume an initial topping in the form of string. Since MatSelect returns array, we will convert this to array and assign it to toppings selected
initialToppings$: Observable<string> = of('Onion, Pepperoni, Tomato'); 
initialToppingListArray$: Observable<string[]> = this.initialToppings$.pipe(
  map(toppingList => toppingList.split(',')),
  tap(toppings => this.toppings.patchValue(toppings))
);

// Next we define toppings and toppingsValue to extract toppings and toppings as a string from the form group
get toppings(): FormControl {
  return this.demandeDevis.get('toppings') as FormControl
};

get toppingsValue(): string {
  return this.toppings.value.join(',')
}

// Finally I will combine allToppings$ and initialToppingListArray$ to use one async pipe in the HTML
v$ = forkJoin([this.allToppings$, this.initialToppingListArray$]).pipe(
  map(([allToppings]) => ({ allToppings}))
)

En el HTML

<form [formGroup]="demandeDevis" *ngIf='v$ | async as v'>
<mat-form-field appearance="fill">
  <mat-label>Toppings</mat-label>
  <mat-select formControlName="toppings" multiple>
    <mat-option *ngFor="let topping of v.allToppings" [value]="topping">{{topping}}</mat-option>
  </mat-select>
</mat-form-field>

<button (click)="validateForm()" >
  Validate (console.log) 
  </button>
</form>


TOPPINGS VALUE: {{ toppingsValue }}

Ahora puede acceder a la lista como una cadena separada usando toppingsValue

Ver muestra en Stackblit

1
yivi 14 oct. 2020 a las 18:27

Deberá crear un control personalizado

Ver solución de trabajo

app-string-select.ts

import { Component, forwardRef, OnInit } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
import { Observable, of } from "rxjs";

@Component({
  selector: "app-string-select",
  templateUrl: "./string-select.component.html",
  styleUrls: ["./string-select.component.css"],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => StringSelectComponent),
      multi: true
    }
  ]
})
export class StringSelectComponent implements ControlValueAccessor {
  value: string[] = [];
  allToppings$: Observable<string[]> = of([
    "Extra cheese",
    "Mushroom",
    "Onion",
    "Pepperoni",
    "Sausage",
    "Tomato"
  ]);
  onChange: any = () => {};
  onTouched: any = () => {};
  constructor() {}
  writeValue(value: string): void {
    this.value = value.split(",");
  }
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
  emitChange() {
    this.onChange(this.value.join(","));
  }
}

app-string-select.html

<mat-form-field appearance="fill">
  <mat-label>Toppings</mat-label>
  <mat-select [(ngModel)]="value" (ngModelChange)='emitChange()' multiple>
    <mat-option *ngFor="let topping of allToppings$ | async" [value]="topping">{{topping}}</mat-option>
  </mat-select>
</mat-form-field>

select-multiple-example.ts

import {ChangeDetectionStrategy, Component} from '@angular/core';
import {FormControl, FormGroup, FormBuilder} from '@angular/forms';
import {Observable, of } from 'rxjs';
import {tap } from 'rxjs/operators';

/** @title Select with multiple selection */
@Component({
  selector: 'select-multiple-example',
  templateUrl: 'select-multiple-example.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class SelectMultipleExample {

  demandeDevis: FormGroup = this.formBuilder.group({ toppings: ['']});

  initialToppings$: Observable<string> = of('Onion,Pepperoni,Tomato').pipe(
    tap(toppings => this.toppings.patchValue(toppings))
  )

  get toppings(): FormControl {
    return this.demandeDevis.get('toppings') as FormControl
  };

  constructor(private formBuilder: FormBuilder) {}

  validateForm(){
    const valuesForm = this.toppings.value;
    console.log(valuesForm); 
  }
}

select-multiple-example.html

<form [formGroup]="demandeDevis" *ngIf="initialToppings$ | async">
<app-string-select formControlName='toppings'></app-string-select>

<div>
   <button (click)="validateForm()" >
    Validate
  </button>
</div>
</form>
1
Owen Kelvin 15 oct. 2020 a las 13:42