如何在角度8中生成动态反应形式 [英] How to generate dynamically reactive forms in angular 8

查看:57
本文介绍了如何在角度8中生成动态反应形式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我提出了有关动态生成表单控制器的问题,此后我对动态模板生成和控制器生成有一些疑问.

I opened question about dynamically generate form controllers,after that I have some issues with dynamically template generate and controllers generate.

在这个项目中,主要是我在数组中有4种类型的问题.我必须动态生成这些问题

in this project,mainly I have 4 types of questions in an array.I have to generate these questions dynamically

问题类型为

  1. MCQ(只需选择一个答案)

  1. MCQ ( only have to select one answer)

多项选择(用户可以选择多个答案,并且至少需要一个答案)

Multiple Select ( User can select multiple answers and at least one required)

排名问题(用户必须给出正确的答案顺序.答案应该是唯一的)

Ranking question ( user have to give the correct order of answers. answers should be unque)

这是我的html代码

<div class="container">
    <div class="row">
        <div class="col-md-12">
            <div class="card">
                <div class="card-header  bg-transparent border-success">
                    <h3>15 questions</h3>
                </div>
                <div class="card-body">
                    <div class="row">
                        <div class="col-md-12">
                            <form [formGroup]="surveyQuestionForm">
                                <div *ngFor="let question of questions; let i=index">
                                    <div [ngSwitch]="question.qType">
                                        <div *ngSwitchCase="1">
                                            <div class="form-group">
                                                <label class="control-label"> {{question.qNo}})
                                                    {{question.question}}</label>
                                                <div class="ml-3">
                                                    <table>
                                                        <tr *ngFor="let anwr of question.answers; let a=index">
                                                            <td>{{a+1}}. {{anwr}} </td>
                                                            <td>
                                                                <div class="custom-radio custom-control">
                                                                    <input type="radio" class="custom-control-input"
                                                                        id="q{{question.qNo}}_{{a}}"
                                                                        name="q{{question.qNo}}" value="{{a+1}}"
                                                                        formControlName="q{{question.qNo}}"
                                                                        [ngClass]="{'is-invalid':surveyQuestionForm.get('q'+ question.qNo).errors && formSubmitted}" />
                                                                    <label class="custom-control-label"
                                                                        for="q{{question.qNo}}_{{a}}"></label>
                                                                </div>
                                                            </td>
                                                        </tr>
                                                        <div class="text-danger"
                                                            *ngIf="surveyQuestionForm.get('q'+ question.qNo).hasError('required') && formSubmitted">
                                                            Answer required</div>
                                                    </table>

                                                </div>
                                            </div>
                                        </div>
                                        <div *ngSwitchCase="2">
                                            <div class="form-group">
                                                <label class="control-label"> {{question.qNo}})
                                                    {{question.question}}</label>
                                                <div class="ml-3">
                                                    <table>
                                                        <tr *ngFor="let anwr of question.answers; let b=index">
                                                            <td>{{b+1}}. {{anwr}} </td>
                                                            <td>
                                                                <div class="custom-checkbox custom-control">
                                                                    <input type="checkbox" class="custom-control-input"
                                                                        id="q{{question.qNo}}_{{b}}" value="{{b+1}}"
                                                                        formControlName="q{{question.qNo}}"
                                                                        [ngClass]="{'is-invalid':surveyQuestionForm.get('q'+ question.qNo).errors && formSubmitted}" />
                                                                    <label class="custom-control-label"
                                                                        for="q{{question.qNo}}_{{b}}"></label>
                                                                </div>
                                                            </td>
                                                        </tr>
                                                        <div class="text-danger"
                                                            *ngIf="surveyQuestionForm.get('q'+ question.qNo).hasError('atLeastOneRequired') && formSubmitted">
                                                            At least One Answer required</div>
                                                    </table>

                                                </div>
                                            </div>
                                        </div>
                                        <div *ngSwitchCase="3">
                                            <div class="form-group">
                                                <label class="control-label"> {{question.qNo}})
                                                    {{question.question}}</label>
                                                <div class="ml-3">
                                                    <table>
                                                        <tr *ngFor="let anwr of question.answers; let a=index">
                                                            <td>{{a+1}}. {{anwr}} </td>
                                                            <div class="invalid-feedback"
                                                                *ngIf="surveyQuestionForm.get('q'+ question.qNo).touched && surveyQuestionForm.get('q'+ question.qNo).hasError('required')">
                                                                Answer required</div>
                                                            <div class="invalid-feedback"
                                                                *ngIf="surveyQuestionForm.get('q'+ question.qNo).touched && surveyQuestionForm.get('q'+ question.qNo).hasError('max')">
                                                                max value</div>
                                                            <div class="invalid-feedback"
                                                                *ngIf="surveyQuestionForm.get('q'+ question.qNo).touched && surveyQuestionForm.get('q'+ question.qNo).hasError('min')">
                                                                min value</div>
                                                            <div class="invalid-feedback"
                                                                *ngIf="surveyQuestionForm.get('q'+ question.qNo).touched && surveyQuestionForm.get('q'+ question.qNo).hasError('notAllUnique')">
                                                                Already inserted value</div>
                                                            <td>
                                                                <input type="number" style="width:40px;"
                                                                    id="q{{question.qNo}}_{{a}}"
                                                                    [ngClass]="{'is-invalid': surveyQuestionForm.get('q'+ question.qNo).errors 
                                                                    && surveyQuestionForm.get('q'+ question.qNo).touched}"
                                                                    formControlName="q{{question.qNo}}"
                                                                    class="text-center" />
                                                            </td>
                                                        </tr>
                                                    </table>
                                                </div>
                                            </div>
                                        </div>
                                        <div *ngSwitchCase="4">
                                            <div class="form-group">
                                                <label class="control-label"> {{question.qNo}})
                                                    {{question.question}}</label>
                                                <div class="ml-3">
                                                    <table>
                                                        <th width="auto"></th>
                                                        <th></th>

                                                        <tr>

                                                            <td><textarea class="form-control" rows="5" id="comment" name="text"
                                                                [ngClass]="{'is-invalid':surveyQuestionForm.get('q'+ question.qNo).errors && 
                                                                surveyQuestionForm.get('q'+ question.qNo).touched}"
                                                                formControlName="q{{question.qNo}}"></textarea></td>
                                                        </tr>
                                                        <div class="text-danger"
                                                            *ngIf="surveyQuestionForm.get('q'+ question.qNo).hasError('required') && formSubmitted">
                                                            Answer required</div>
                                                    </table>
                                                </div>
                                            </div>
                                        </div>
                                        <div *ngSwitchCaseDefault></div>
                                    </div>

                                </div>


                            </form>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-12">
                            <button (click)="onSubmit()" class="btn btn-primary">Submit</button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

这是我的打字稿代码

surveyQuestionForm: FormGroup;
  formSubmitted = false;

  constructor(private fb: FormBuilder) { }
  questions: any = [
    {
      id: 11,
      surveyNo: 5,
      qNo: 1,
      question: 'What is the country you would like to travel?',
      qType: 1,
      noAnswrs: 4,
      answerType: 1,
      answers: ['America', 'Australia', 'India', 'England']
    },
    {
      id: 12,
      surveyNo: 5,
      qNo: 2,
      question: 'What type of credit cards do you have?',
      qType: 2,
      noAnswrs: 4,
      answerType: 1,
      answers: ['Visa', 'Mastercard', 'American Express', 'Discover']
    },
    {
      id: 13,
      surveyNo: 5,
      qNo: 3,
      question: 'Please rank the following features in order of importance,where 1 is the most important to you.?',
      qType: 3,
      noAnswrs: 4,
      answerType: 1,
      answers: ['Location', 'Confort', 'Service', 'Value for money']
    },
    {
      id: 14,
      surveyNo: 5,
      qNo: 4,
      question: 'What is your idea about our institute?',
      qType: 4,
      noAnswrs: 0,
      answerType: 1,
      answers: []
    }
  ];
  ngOnInit() {
    this.createForms();
  }
  createForms(): any {
    this.surveyQuestionForm = this.fb.group(
      this.questions.reduce((group: any, question: { qNo: string; }) => {
        return Object.assign(group, { ['q' + question.qNo]: this.buildSubGroup(question) });
      }, {})
    );
  }

  private buildSubGroup(question) {
    switch (question.qType) {
      case 1:
        return [Validators.required];
      case 2:
        return this.fb.group(
          question.answers.reduce((subGroup, answer) => {
            return Object.assign(subGroup, { [answer]: [false] });
          }, {}), { validators: [this.atLeastOneRequired()] }
        );
      case 3:
        return this.fb.group(
          question.answers.reduce((subGroup, answer) => {
            return Object.assign(subGroup, { [answer]: ['', [Validators.required, Validators.min(1), Validators.max(3)]] });
          }, {}), { validators: [this.uniqueNumbersValidator()] }
        );
      case 4:
        return this.fb.group({ answer: ['', [Validators.required]] });
      default:
        throw new Error('unhandled question type');
    }
  }



  atLeastOneRequired() {
    return (ctrl: AbstractControl) => {
      const fg = ctrl as FormGroup;
      const atLeastOneTrue = Object.values(fg.controls).some(fc => !!fc.value);
      return (atLeastOneTrue) ? null : { atLeastOneRequired: true };
    };
  }

  uniqueNumbersValidator() {
    return (ctrl: AbstractControl) => {
      const fg = ctrl as FormGroup;
      let allUnique = true;
      const values = [];
      Object.values(fg.controls).forEach(fc => {
        const val = fc.value;
        if (val && allUnique) {
          if (values.includes(val) && allUnique) {
            allUnique = false;
          }
          values.push(val);
        }
      });
      return (allUnique) ? null : { notAllUnique: true };
    };
  }

  onSubmit() {
    this.formSubmitted = true;
    console.log(this.formSubmitted);
  }

我可以看到此错误,

control.registerOnChange不是函数

control.registerOnChange is not a function

这是stackblitz链接 https://stackblitz.com/edit/angular-nya7l9

here is the stackblitz link https://stackblitz.com/edit/angular-nya7l9

请帮助我解决此问题.

谢谢

推荐答案

首先,建立和绑定无线电:

first, issue with your radio building and binding:

像这样构建它:

  case 1:
  case 4:
    return this.fb.group({ answer: ['', [Validators.required]] });

并这样绑定:

  <div class="form-group" formGroupName="{{'q' + question.qNo}}">
      <label class="control-label"> {{question.qNo}})
          {{question.question}}</label>
      <div class="ml-3">
          <table>
              <tr *ngFor="let anwr of question.answers; let a=index">
                  <td>{{a+1}}. {{anwr}} </td>
                  <td>
                      <div class="custom-radio custom-control">
                          <input type="radio" class="custom-control-input"
                              id="q{{question.qNo}}_{{a}}"
                              name="answer" value="{{a+1}}"
                              formControlName="answer"
                              [ngClass]="{'is-invalid':surveyQuestionForm.get('q'+ question.qNo).errors && formSubmitted}" />
                          <label class="custom-control-label"
                              for="q{{question.qNo}}_{{a}}"></label>
                      </div>
                  </td>
              </tr>
              <div class="text-danger"
                  *ngIf="surveyQuestionForm.get('q'+ question.qNo).hasError('required') && formSubmitted">
                  Answer required</div>
          </table>

      </div>
  </div>

首先使用formGroupName指令,然后静态访问答案控件.

use the formGroupName directive up top then just access the answer control statically.

下一步您的复选框绑定:

next your checkbox binding:

<div class="form-group" formGroupName="{{'q' + question.qNo}}">
    <label class="control-label"> {{question.qNo}})
        {{question.question}}</label>
    <div class="ml-3">
        <table>
            <tr *ngFor="let anwr of question.answers; let b=index">
                <td>{{b+1}}. {{anwr}} </td>
                <td>
                    <div class="custom-checkbox custom-control">
                        <input type="checkbox" class="custom-control-input"
                            id="q{{question.qNo}}_{{b}}" value="{{b+1}}"
                            formControlName="{{anwr}}"
                            [ngClass]="{'is-invalid':surveyQuestionForm.get('q'+ question.qNo).errors && formSubmitted}" />
                        <label class="custom-control-label"
                            for="q{{question.qNo}}_{{b}}"></label>
                    </div>
                </td>
            </tr>
            <div class="text-danger"
                *ngIf="surveyQuestionForm.get('q'+ question.qNo).hasError('atLeastOneRequired') && formSubmitted">
                At least One Answer required</div>
        </table>

    </div>
</div>

再次使用formGroupName指令,因为您的整体表单只是一组组,然后在其中,您的formControlNames就是答案本身.

again, use the formGroupName directive since your overall form is just a group of groups, then within, your formControlNames are the answers themselves.

现在您的多项选择绑定,通常存在相同的问题:

now your multiple choice binding, generally the same issues:

<div class="form-group" formGroupName="{{'q' + question.qNo}}">

<input type="number" style="width:40px;"
    id="q{{question.qNo}}_{{a}}"
    [ngClass]="{'is-invalid': surveyQuestionForm.get('q'+ question.qNo).errors 
    && surveyQuestionForm.get('q'+ question.qNo).touched}"
    formControlName="{{anwr}}"
    class="text-center" />

最后,您的自由文本答案(基本上是相同的问题)需要formGroupName指令,并正确绑定到其中的静态答案控件:

finally, your free text answer, basically the same problems, need the formGroupName directive, and to bind correctly to the static answer control within it:

<td><textarea class="form-control" rows="5" id="comment" name="text"
    [ngClass]="{'is-invalid':surveyQuestionForm.get('q'+ question.qNo).errors && 
    surveyQuestionForm.get('q'+ question.qNo).touched}"
    formControlName="answer"></textarea></td>

固定的闪电战:

https://stackblitz.com/edit/angular-d4p6ly?file=src/app/app.component.html

这篇关于如何在角度8中生成动态反应形式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆