【问题标题】:Angular 10 - Convert FormControl array values to Strings separated with commasAngular 10 - 将 FormControl 数组值转换为用逗号分隔的字符串
【发布时间】:2021-01-22 05:42:25
【问题描述】:

编辑 1:

我修改了我的问题以澄清我的需求。

我有一个包含FormControlFormGroup

在这些FormControl中,有一个接收数组值。

我正在寻找的是是否有一种解决方案可以让FormControl 接收数组值,而不是接收逗号分隔的字符串值中的值(不带括号 [] )。

我得到了什么:(数组值)

我想要什么:(字符串值用逗号分隔,没有brackets[]

分叉链接:Here

  • 提前感谢您的帮助

原问题:

我想将从FormArray 接收到的数据转换为带逗号的字符串。

我设法在 Console.log 中做到了这一点,但我不知道如何将转换后的数据发送到 FormGroup

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

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

当我按照这些步骤操作时,我会在“Accessoire”上获得null,并在“Accessoire”上获得数组值。

我正在寻找的是从复选框列表中选择的值并将它们转换为带逗号的字符串。我不想以数组形式发送它们。

提前感谢您的解决方案。

编辑 1:

我使用了 @akash 解决方案的第一个选项,它正在工作。我有一个小问题。当我在input 上选择值时,我想将其发送到formControl ...我得到带括号的数组形式...我想要的是带逗号的字符串形式。这是我的问题的链接: https://stackblitz.com/edit/reactive-form-string-values

【问题讨论】:

  • 在 stackblitz 上提供最少的复制可以让人们帮助您,而无需猜测问题是什么,您可能会得到更多的答案
  • 你不能简单地用 var string = array.join() 做到这一点吗?还是我错过了什么?

标签: angular angular-reactive-forms formarray


【解决方案1】:
<mat-select 
      [value]="toppings.value?toppings?.value.split(','):null" 
      (selectionChange)="toppings.setValue($event.value.join(','))"
       multiple>
...
</mat-select>

记住FormControl 存在,即使您没有输入。好吧,你需要重写你所有的代码来接收一个字符串,比如this forked stackblitz

【讨论】:

  • 它正在工作!这就是我一直在寻找的 :) 谢谢@Eliseo 的回答。 感谢大家对这个话题的帮助 :)
【解决方案2】:

更新 2

要从 db 值填充表单,只需初始化控件 toppings,如下所示(参见 this fork)-

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

更新 1

我想我误解了你想要达到的目标。请了解角度 FormGroup 的工作原理。 FormGroup 具有控件字段,这是您在下面作为对象传递的内容。该对象是一个键值对,其中键是您的控件名称(浇头),值是您的控件(例如,FormControl、FormArray 或 FormGroup)-

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

因此,当您执行this.demandeDevis.value 时,您会在相应控件中获得具有相同键(浇头)和值的对象。您可以使用下面的代码来获取toppings 的逗号分隔值。不确定这是否是您要查找的内容,因为这很明显(请参阅this fork)-

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

原答案

如果您对 UI 外观的不同方式持开放态度,请使用 angular material

选项 1

使用mat-select 组件。使用下面的示例,您无需处理选项的选择/取消选择。请看this example on 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>

选项 2

如果您不想使用下拉菜单,请使用mat-selection-list,请参阅this example。下面的示例使用对mat-selection-list 的引用来获取组件中选定选项的列表 -

<mat-selection-list #shoes (selectionChange)=selectionChange()>
  <mat-list-option [value]="shoe" *ngFor="let shoe of typesOfShoes">
    {{shoe}}
  </mat-list-option>
</mat-selection-list>
{{selectedValuesG}}

【讨论】:

  • 我使用了第一个选项并且它正在工作。我有一个小问题。当我获得在输入​​上选择的值时,我想将其发送到 formControl ...我得到带括号的数组形式...我想要的是带逗号的字符串形式。这是我的问题的链接:stackblitz.com/edit/reactive-form-string-values
  • @Akash 是的!这就是我想要做的(你更新的答案),但我想将分隔的逗号值推送到 FormControl ['toppings'] 以将所有表单值推送到数据库......请参阅链接stackblitz.com/edit/… 谢谢 :)
  • @Akash 我看到了你的新答案,但我正在寻找的是当我验证表单时,我不想在“toppings”中发送一个数组,但是我选择的选项中带有逗号的单独字符串(例如方法 join() ),但我不知道如何将其放入代码中。这是更好地解释的图片链接:i.imgur.com/pXr5flf.png再次感谢您的帮助:)
  • 我不知道你为什么想要一个逗号分隔的字符串? mat-select 需要一个数组,您必须传递一个数组。这就是它的工作原理。除非你能解释需要用逗号分隔的字符串吗?如果你想把它作为字符串保存到db,你可以随时转换它。
  • @Akash 我的伙伴有一个使用 Spring Boot 和 MySQL 构建的后端,当我将表单数据发送到数据库时,一切正常,除了附件字段,它是数组形式。在 MySQL 数据库的附件字段中,我得到类似 [java.lang.strxhYE &] 的内容。这就是为什么我想在将数组值发送到数据库之前将其转换为用逗号值分隔的字符串:)
【解决方案3】:

你可以这样做here

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

您必须将其拆分备份以填充 toppings 数组,但我不确定您是否需要它。

【讨论】:

    【解决方案4】:

    我的解决方案是使用Observable 并在需要时转换数据。

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

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

    现在您可以将列表访问为使用toppingsValue 分隔的字符串

    See Sample on Stackblit

    【讨论】:

    【解决方案5】:

    您需要创建一个自定义控件

    See Working Solution

    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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-18
      • 1970-01-01
      • 1970-01-01
      • 2021-12-06
      • 1970-01-01
      • 2011-06-12
      相关资源
      最近更新 更多