首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >表单控件数组到动态FormGroup中

表单控件数组到动态FormGroup中
EN

Stack Overflow用户
提问于 2022-07-11 16:40:43
回答 1查看 161关注 0票数 0

我正在创建一个动态表单,它使用来自后端的json响应来呈现一个反应性表单。

所以json反应的一个例子是..。

代码语言:javascript
复制
  "controls": [
    {
      "name": "name",
      "label": "Name",
      "value": "",
      "type": "text",
      "validators": {
        "required": true,
        "minLength": 4
      }
    },
 ]
}

然后,ts文件使用formGroup构建formBuilder。但是,我在添加一个formControl复选框数组时遇到了问题.其中一个复选框必须选中,否则表单将无效。所以json看起来..。

代码语言:javascript
复制
{
    "controls": [
        {
            "title": "Which of these items do you want to buy? Check as many as you'd like",
            "name": "items",
            "checkboxOptions": [
              {
                "value": "",
                "label": "Item 1",
                "name": "item1"
              },
              {
                "value": "",
                "label": "Item 2",
                "name": "item2"
              }
            ],
            "type": "checkboxgroup",
            "validators": {
                 "required": true
             }
          }
    ]
}

我可以成功地添加checkboxgroup,因为它是自己的表单组,它有一个表单控件数组。然后我可以将formGroup添加到父formGroup中..。但是我对嵌套formGroup的html部分有问题。

顺便说一句。这就是文本框的呈现方式。

代码语言:javascript
复制
<form [formGroup]='myForm' (keydown.enter)="$event.preventDefault()" novalidate>
        <div *ngFor='let control of formControl.controls'>
            <mat-form-field appearance="outline">
                        <mat-label>{{ control.label }}</mat-label>
                        <input matInput [formControlName]='control.name' [type]='control.type'>
                     
            </mat-form-field>
        </div>
</form>

但我不知道如何使用它自己的验证器来呈现formControl复选框数组。谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-12 10:49:10

您可以创建一个组件,用于存储数组的FormControl。

有些人喜欢

代码语言:javascript
复制
@Component({
  selector: 'mat-checkbox-group',
  template: `
  <span [class.horizontal]="horizontal">
    <ul>
      <li *ngFor="let item of list">
        <mat-checkbox [ngModel]="control.value && 
                         control.value.indexOf(item.value)>=0"
                      (ngModelChange)="update($event,item.value)">
          {{item.text}}
        </mat-checkbox>
      </li>
    </ul>
  </span>
 
  `,
  styles: [
    `
   ul{
     padding:0;
     list-style: none;
    }
    .horizontal li{
      display:inline-block;
      margin-right:.5rem;
      
    }
    
    `,
  ],
})
export class CheckboxGroup {
  list: { value: string | number; text: string }[];
  control: FormControl;
  keys: any;
  log: any;
  horizontal:boolean

  constructor(@Optional() @Attribute('horizontal') _horizontal:any){
    this.horizontal=_horizontal!==undefined && _horizontal!==null?
              _horizontal!=="false":false
  }
  @Input('control') set _control(value: any) {
    this.control = value as FormControl;
  }
  @Input('source') set _source(value: any[]) {
    const type = typeof value[0];
    if (type == 'string' || type == 'number')
      this.list = value.map((x) => ({ value: x, text: '' + x }));
    else {
      const match = [
        ...JSON.stringify(value[0])
          .replace(/\"/g, '')
          .matchAll(/(\w+)\:[^,]*/g),
      ].map((x) => x[1]);
      this.list = value.map((x) => ({ value: x[match[0]], text: x[match[1]] }));
    }
  }
  update(checked: boolean, value: string | number) {
    const oldValue = this.control.value || [];
    if (!checked)
      this.control.setValue(
        oldValue.filter((x: string | number) => x != value)
      );
    else
      this.control.setValue(
        this.list
          .filter(
            (x: any) => x.value == value || oldValue.indexOf(x.value) >= 0
          )
          .map((x) => x.value)
      );
  }
}

允许你写

代码语言:javascript
复制
<mat-checkbox-group [source]="control.checkboxOptions" 
    [control]="myform.get(control.name)" >
</mat-checkbox-group>

小心地,组件允许一个字符串数组、一个对象数组的数字数组作为“源”。第一个属性是值,第二个属性是复选框的标签。

请参阅stackblitz

更新我们可以避免创建新组件,但在本例中,.html如下所示

代码语言:javascript
复制
  <div *ngFor="let control of controlsJson?.controls">
      <div class="form-title">{{ control.title }}</div>

      <div class="bottom-space" *ngIf="control.type === 'checkboxgroup'">
        <ng-container *ngIf="dynamicForm.get(control.name) as ctrl">
          <div *ngFor="let item of control.checkboxOptions">
            <mat-checkbox
              [ngModel]="ctrl.value && ctrl.value.indexOf(item.value) >= 0"
              (ngModelChange)="
                update($event, item.value, control.checkboxOptions, ctrl)
              "
              [ngModelOptions]="{ standalone: true }"
            >
              {{ item.label }} {{ item.value }}
            </mat-checkbox>
          </div>
        </ng-container>
      </div>
    </div>

我们使用

代码语言:javascript
复制
<ng-container *ngIf="dynamicForm.get(control.name) as ctrl">

避免重复dynamicForm.get(control.name)

确保我们使用的是ngModel -这不是班纳纳新税

代码语言:javascript
复制
[ngModel]="ctrl.value && ctrl.value.indexOf(item.value) >= 0"

要控制,我们的更新需要作为参数

  1. $event:true或false根据签入或nor
  2. item.value:选项的值
  3. control.checkboxOptions:选项列表
  4. ctrl: FormControl

函数更新非常类似于我们有组件时。

代码语言:javascript
复制
  update(checked: boolean, value: string | number,options:any[],control:any) {
    const oldValue = control.value || [];
    if (!checked)
      control.setValue(
        oldValue.filter((x: string | number) => x != value)
      );
    else
      control.setValue(
        options
          .filter(
            (x: any) => x.value == value || oldValue.indexOf(x.value) >= 0
          )
          .map((x) => x.value)
      );
  }

但要小心!

我们只有一个uniq FormControl

代码语言:javascript
复制
for (const control of this.controlsJson.controls) {
  if (control.type == 'checkboxgroup') {
      this.dynamicForm.addControl(
        control.name,new FormControl())
    }
  }

当我们定义“选项”时,每个选项的“价值”应该是不同的。

代码语言:javascript
复制
 "checkboxOptions": [
      {
        "value": "false", //<--this value will be store
        "label": "Item 1",
        "name": "item1"
      },
      {
        "value": "true", //<--this value will be store
        "label": "Item 2",
        "name": "item2"
      }
    ],

如果我们想要“至少一个”,那么在创建Validators.required时只需要添加FormControl。更好的是,我们创建一个函数,返回一个基于字符串数组的验证器数组。

想象一下有些人

代码语言:javascript
复制
"validators": ["required","max(3)"]

我们可以做一个函数

代码语言:javascript
复制
  getValidators(validators:string[])
  {
    return validators.map(x=>{
      if (x=="required")
        return Validators.required;
      if (x.substr(0,3)=="max")
      {
        const max=x.match(/max\((\d+)\)/)
        return Validators.max(+max[1])

      }
      ....
      return null //<--if some string not fullfilled any "if"
    }).filter(x=>x)
  }

写一些类似的东西

代码语言:javascript
复制
for (const control of this.controlsJson.controls) {
  if (control.type == 'checkboxgroup') {
      this.dynamicForm.addControl(
        control.name,new FormControl(null,this.getValidators(control.validators)))
    }
  }

叉式堆栈闪电战

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72941882

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档