【问题标题】:Angular dynamic form nested fields角度动态表单嵌套字段
【发布时间】:2019-04-05 14:41:30
【问题描述】:

https://angular.io/guide/dynamic-form 的帮助下,我正在制作一个动态表单,我首先需要显示两个字段。

  new TextboxQuestion({
    key: 'firstName',
    label: 'First name',
    value: '',
    required: true,
    order: 1
  }),

  new TextboxQuestion({
    key: 'lastName',
    label: 'Last name',
    value: '',
    required: true,
    order: 2
  }),

这两个字段需要在加载时首先出现。

在此之后,我将有两个按钮作为add and remove

  <button (click)="addNew()"> Add </button> &nbsp;&nbsp;&nbsp;
  <button (click)="removeNew()"> Remove </button> <br><br>

通过点击添加,我需要显示接下来的两个字段(以下字段),

  new TextboxQuestion({
    key: 'emailAddress',
    label: 'Email',
    type: 'email',
    order: 3
  }),

  new DropdownQuestion({
    key: 'brave',
    label: 'Bravery Rating',
    options: [
      {key: 'solid',  value: 'Solid'},
      {key: 'great',  value: 'Great'},
      {key: 'good',   value: 'Good'},
      {key: 'unproven', value: 'Unproven'}
    ],
    order: 4
  })

订单 1 和 2 处于初始状态,点击添加后需要显示下两个订单 3 和 4。

请帮我实现点击添加按钮添加子字段的结果。

一次显示所有工作的堆栈闪电战,https://stackblitz.com/edit/angular-x4a5b6

【问题讨论】:

    标签: javascript angular typescript angular-reactive-forms angular4-forms


    【解决方案1】:

    用formArray实现动态表单

    嗯,事情更复杂。我做了一个stackblik,见demo

    我将尝试解释如何扩展 https://angular.io/guide/dynamic-form 以允许表单数组。

    首先我们需要创建一个新类型的问题,一个 questionArray

    import { QuestionBase } from './question-base';
    
    export class ArrayQuestion extends QuestionBase<string> {
      controlType = 'array';
      type: any;
    
      constructor(options: {} = {}) {
        super(options);
      }
    }
    

    我们必须更改问题库以添加新属性“children”

    export class QuestionBase<T> {
      value: T;
      ...
      children:any[];
    
      constructor(options: {
          value?: T,
          ...
          children?:any
        } = {}) {
        this.value = options.value;
        ...
        this.children=options.children || null;
      }
    }
    

    添加更改问题控制服务以允许管理 formArrays

    toFormGroup(questions: QuestionBase<any>[]) {
        let group: any = {};
    
        questions.forEach(question => {
          //If the control type is "array" we create a FormArray
          if (question.controlType=="array") {
             group[question.key]=new FormArray([]);
          }
          else {
            group[question.key] = question.required ? new FormControl(question.value || '', Validators.required)
              : new FormControl(question.value || '');
          }
        });
        return new FormGroup(group);
      }
    

    好吧,我们将 dynamic-form.component 转换为显示一个 FormArray

    <div *ngFor="let question of questions" class="form-row">
        <ng-container *ngIf="question.children">
            <div [formArrayName]="question.key">
                <div *ngFor="let item of form.get(question.key).controls; let i=index" [formGroupName]="i">
                    <div *ngFor="let item of question.children">
                        <app-question [question]="item" [form]="form.get(question.key).at(i)"></app-question>
                    </div>
                </div>
            </div>
        </ng-container>
        <ng-container *ngIf="!question.children">
            <app-question [question]="question" [form]="form"></app-question>
    
        </ng-container>
    </div>
    

    就这样吧。那么,如何增加和减少 formArrays?我们有两个按钮

      <button (click)="addControls('myArray')"> Add </button>
      <button (click)="removeControls('myArray')"> Remove </button> <br><br>
    

    还有两个函数addControls和removeControls

      addControls(control: string) {
        let question: any = this.questions.find(q => q.key == control);
        let children = question ? question.children : null;
        if (children)
          (this.form.get(control) as FormArray).push(this.qcs.toFormGroup(children))
      }
      removeControls(control: string){
        let array=this.form.get(control) as FormArray;
        array.removeAt(array.length-1);
      }
    

    更新我忘了添加问题和示例:

    let questions: QuestionBase<any>[] = [
    
          new TextboxQuestion({
            key: 'firstName',
            label: 'First name',
            value: '',
            required: true,
            order: 1
          }),
    
          new TextboxQuestion({
            key: 'lastName',
            label: 'Last name',
            value: '',
            required: true,
            order: 2
          }),
          new ArrayQuestion({
            key: 'myArray',
            value: '',
            order: 3,
            children: [
              new TextboxQuestion({
                key: 'emailAddress',
                label: 'Email',
                type: 'email',
                order: 3
              }),
              new DropdownQuestion({
                key: 'brave',
                label: 'Bravery Rating',
                options: [
                  { key: 'solid', value: 'Solid' },
                  { key: 'great', value: 'Great' },
                  { key: 'good', value: 'Good' },
                  { key: 'unproven', value: 'Unproven' }
                ],
                order: 4
              })
            ]
          })
        ];
    

    【讨论】:

    • Eliseo 非常感谢.. 我希望在看到 stackblitz 之后一切都会好起来.. 如果有任何疑问会回复给你..
    • Eliseo,我已经发布了另一个问题stackoverflow.com/questions/53113962/… 以从 JSON 加载数据作为输入,它只是您的解决方案,但我需要单独为每个输入提供 JSON 数据。如果您参考你会很好理解的问题..你能帮我吗??
    • 嗨,Eliseo,这是您stackoverflow.com/questions/53220425/… 的另一个新问题,用于在编辑期间将数据修补到这些表单元素..
    【解决方案2】:

    您唯一需要的是使用切片和变量“页面”对问题“分页”

    即:

      //add a variable "page" in your dinamic-form.component.ts
      page:number=0;
    

      //in your dinamic-form.component.html, change the *ngFor like
      <form (ngSubmit)="onSubmit()" [formGroup]="form">
        <div *ngFor="let question of questions.slice(page*2,(page+1)*2)" class="form-row">
          <app-question [question]="question" [form]="form"></app-question>
        </div>
       ....
      </form>
    

    然后,你的按钮添加可以像

      <button (click)="page=page+1"> Add </button>
    

    【讨论】:

    • 感谢您的帮助.. 请提供可以帮助我的 stackblitz.. 我已经实现了您的代码,但我无法获得任何输入 stackblitz.com/edit/angular-x4a5b6
    • 您忘记添加属性“页面”。在您的 dinamic-form.component.ts 中,您需要在指令之后添加 page:number=0:payLoad=''
    • 如果我单击添加,那么旧的输入文本框将被隐藏,接下来的两个即将到来。我需要在初始时显示前两个,然后单击添加,接下来的两个应该会出现向下并再次单击添加添加的两个文本框(顺序 3 和 4)需要在每次单击添加时绑定。我需要在单击添加按钮时显示两个顺序(1 和 2)。我希望你在半路帮助我..请Eliseo我请求你帮助我,这将更加明显..
    • 只需将切片替换为切片(0,(page+1)*2)。这个想法是,您不会在每个时刻都只显示您需要的所有“问题”。我想你想每次只显示两个
    • 只是最后一个问题。再次单击添加时,我应该在每次单击添加按钮时附加顺序(3 和 4)。您是唯一帮助我的人很多..请单独回答这个..我一定会接受你的回答..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-01
    • 2014-07-14
    相关资源
    最近更新 更多