首页 > 解决方案 > 角嵌套动态表单

问题描述

如何以 angular.io 文档的方式制作嵌套形式:

https://stackblitz.com/angular/pbdkbbnmrdg

目标是在名为“details”的子表单组中有两个来自 question.service.ts 的 DropdownQuestion,其他所有内容都像现在这样在父表单中......所以最后看起来像这样:

{
    "firstName":"Bembasto",
    "email":"something@email.com",
    "details": {
      "dropdown1":{

      },
      "dropdown2":{

      }
    }
}

标签: angularangular-forms

解决方案


Uros,您需要了解代码如何创建 FormGroup 以及如何创建输入。

我们有一个复杂的对象,它习惯于

  1. 创建表单
  2. 显示输入

首先我们要创建一种新型的控制问题组

import { QuestionBase } from './question-base';

export class GroupQuestion extends QuestionBase<string> {
  controlType = 'group';
  type: string;

  constructor(options: {} = {}) {
    super(options);
  }
}

并为问题库添加一个新属性

questions:any[];
//and change the constructor to allow give value
constructor(options: {
      value?: T,
      ...
      questions?:any[]
    } = {}) {
    this.value = options.value;
    ...
    this.questions = options.questions || [];
  }

看看代码是如何创建表单的。它是在 question-control.service 中制作的。更改函数 toFormGroup 以考虑 typeControl “组”

toFormGroup(questions: QuestionBase<any>[] ) {
    let group: any = {};

    questions.forEach(question => {
      group[question.key] =  (question.controlType=='group')?
      this.toFormGroup(question.questions)
      :question.required ? new FormControl(question.value || '', Validators.required)
                                              : new FormControl(question.value || '');
    });
    return new FormGroup(group);
  }

是的,我们使用的是递归函数。我们的想法是我们将有一个问题对象,例如

let questions: QuestionBase<any>[] = [
  new DropdownQuestion({
    ...
  }),
  new TextboxQuestion({
    ...
  })
  , new GroupQuestion(
    {
      key: 'details',
      label: 'Details',
      order: 2,
      questions: [
        new TextboxQuestion({
            ...
        }),
        new DropdownQuestion({
            ...
        })
      ]
    }
  )
];

好吧,有了这些更改,我们还没有创建 formGroup,但是,我们如何显示输入?之前,我们将更改 dinamic-form-component 以允许将“表单”作为参数传递

  @Input() form: FormGroup;
  subGroup:boolean=true;

  ngOnInit() {
    if (!this.form)
    {
      this.form = this.qcs.toFormGroup(this.questions);
      this.subGroup=false;
    }
  }

我们添加了一个新属性“subGroup”来指示是否是子组。所以,我们可以隐藏“提交”按钮。

最后,我们更改了 dynamic-form-question.component.html 以考虑“组问题”

<div [formGroup]="form">
  <label [attr.for]="question.key">{{question.label}}</label>

  <div [ngSwitch]="question.controlType">
    <input *ngSwitchCase="'textbox'" ...>
    <select *ngSwitchCase="'dropdown'" ...>
    </select>

    <div *ngSwitchCase="'group'" [formGroupName]="question.key">
       <app-dynamic-form [form]="form.get(question.key)"
           [questions]="question.questions"></app-dynamic-form>
    </div>
  </div> 

  <div  class="errorMessage" *ngIf="!isValid">{{question.label}} is required</div>

</div>

是的,如果我们有一个小组问题,我们会以“form.get(question.key)”的形式显示一个 app-dinamic-form pass。这就是我们更改 dinamic-form-component 的原因:允许传递一个 formGroup,如果不传递值则只创建一个新表单。

在这个stackblitz中是完整的例子

注意:我个人不喜欢创建 formGroup 的组件。我喜欢在 main.component 中创建 formGroup 并作为参数传递

this other stackblitz 中探索这个想法。应用程序组件有一个 ngOnInit 进行两次调用

ngOnInit()
  {
    this.questions = this.service.getQuestions();
    this.form=this.qcs.toFormGroup(this.questions);
  }

我们需要手动为动态形式的属性“子组”赋值


推荐阅读