【问题标题】:How to create form controllers dynamically in angular 2+ using Reactive forms如何使用反应式表单以 Angular 2+ 动态创建表单控制器
【发布时间】:2019-07-20 23:43:48
【问题描述】:

我有一个问题数组。我必须阅读它并动态显示问题。所以我有几个与它相关的问题。

1) 我不知道如何将控制器初始化为 FormBuilder 实例。

2) 如何动态创建问题

3) 如何动态添加验证

我使用 Angular 8 创建了这个项目。

我在调查中主要有 4 种类型的问题。

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

  2. 多选(用户可以选择多个答案)

  3. 排名问题(用户必须给出正确的答案顺序)

  4. 描述性(用户自己的答案可以给出)

这是我的问题数组

questions: any = [
{
  id: 11,
  surveyNo: 5,
  qNo: 1,
  question: 'What is the country you would like to travel?',
  qType: 1,
  noAnswrs: 4,
  answerType: 1,
  answrs: ['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,
  answrs: ['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,
  answrs: ['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,
  answrs: []
}];

这里是html代码

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

<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 class="form-group">
                                    <label class="control-label"> 1) What is the country you would like to
                                        travel?</label>
                                    <div class="ml-3">
                                        <table>
                                            <th width="auto"></th>
                                            <th width="auto"></th>
                                            <tr>
                                                <td>1. America</td>
                                                <td>
                                                    <div class=" custom-radio custom-control">
                                                        <input type="radio" class="custom-control-input" id="q1_1"
                                                            name="q1" value="1" formControlName="q1" />
                                                        <label class="custom-control-label" for="q1_1">

                                                        </label>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <td>2. Australia </td>
                                                <td>
                                                    <div class=" custom-radio custom-control">
                                                        <input type="radio" class="custom-control-input" id="q1_2"
                                                            name="q1" value="2" formControlName="q1" />
                                                        <label class="custom-control-label" for="q1_2"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <td>3. India </td>
                                                <td>
                                                    <div class="custom-radio custom-control">
                                                        <input type="radio" class="custom-control-input" id="q1_3"
                                                            name="q1" value="3" formControlName="q1" />
                                                        <label class="custom-control-label" for="q1_3"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <td>4. England </td>
                                                <td>
                                                    <div class=" custom-control  custom-radio">
                                                        <input type="radio" class="custom-control-input" id="q1_4"
                                                            name="q1" value="4" formControlName="q1" />
                                                        <label class="custom-control-label" for="q1_4"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                        </table>





                                    </div>
                                </div>
                               
                                <div class="form-group">
                                    <label class="control-label"> 2) What type of credit cards do you have?</label>
                                    <div class="ml-3">
                                        <table>
                                            <th width="auto"></th>
                                            <th width="auto"></th>
                                            <tr>
                                                <td>1. Visa </td>
                                                <td>
                                                    <div class="custom-control custom-checkbox">
                                                        <input type="checkbox" class="custom-control-input" id="q2_1"
                                                            value="1" formControlName="q2" />
                                                        <label class="custom-control-label" for="q2_1"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <td>2. Mastercard</td>
                                                <td>
                                                    <div class="custom-control custom-checkbox">
                                                        <input type="checkbox" class="custom-control-input" id="q2_2"
                                                            value="2" formControlName="q2" />
                                                        <label class="custom-control-label" for="q2_2"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <td>3. American Express</td>
                                                <td>
                                                    <div class="custom-control custom-checkbox">
                                                        <input type="checkbox" class="custom-control-input" id="q2_3"
                                                            value="3" formControlName="q2" />
                                                        <label class="custom-control-label" for="q2_3"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <td>4. Discover</td>
                                                <td>
                                                    <div class="custom-control custom-checkbox">
                                                        <input type="checkbox" class="custom-control-input" id="q2_4"
                                                            value="4" formControlName="q2" />
                                                        <label class="custom-control-label" for="q2_4"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                        </table>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label class="control-label"> 3) Please rank the following features in order of importance,where 1 is the most important to you.?</label>
                                    <div class="ml-3">
                                        <table>
                                             
                                            <tr>
                                                <td>1. Location </td>
                                                <div class="invalid-feedback"
                                                 *ngIf="surveyQuestionForm.get('q3').touched && surveyQuestionForm.get('q3').hasError('required')">Answer required</div>
                                                 <div class="invalid-feedback"
                                                 *ngIf="surveyQuestionForm.get('q3').touched && surveyQuestionForm.get('q3').hasError('max')">max value</div>
               
                                                <td><input type="number" style="width:40px;" id="q3_1"  
                                                    [ngClass]="{'is-invalid': surveyQuestionForm.get('q3').errors && surveyQuestionForm.get('q3').touched}"
                                                        formControlName="q3" class="text-center" /></td>
                                            </tr>
                                              <tr>
                                                <td>2. Confort </td>
                                                <td><input type="number" style="width:40px;" id="q3_1"  
                                                         class="text-center" /></td>
                                            </tr>
                                            <tr>
                                                <td>3. Service </td>
                                                <td><input type="number" style="width:40px;" id="q3_1"  
                                                          class="text-center" /></td>
                                            </tr>
                                            <tr>
                                                <td>4. Value for money </td>
                                                <td><input type="number" style="width:40px;" id="q3_1"  
                                                          class="text-center" /></td>
                                            </tr>
                                        </table>


                                    </div>
                                </div>
                                <div class="form-group">
                                    <label class="control-label"> 4) What is your idea about our institute?</label>
                                    <div class="ml-3">
                                        <table>
                                            <th width="auto"></th>
                                            <th></th>

                                            <tr>

                                                <td><textarea class="form-control" rows="5" id="comment" name="text"
                                                        formControlName="q4"></textarea></td>
                                            </tr>

                                        </table>


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

这是打字稿代码

 surveyQuestionForm: FormGroup;
  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,
      answrs: ['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,
      answrs: ['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,
      answrs: ['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,
      answrs: []
    }
  ];
  ngOnInit() {
    this.createForms();
  }
  createForms(): any {
    this.surveyQuestionForm = this.fb.group({
      q1: ['', [Validators.required]],
      q2: ['', [Validators.required]],
      q3: ['', [Validators.required, Validators.min(1), Validators.max(3)]],
      q4: ['', [Validators.required]]
     });
  }

这是问题预览

这里是必须使用的验证器

  1. 必需的验证器
  2. 最小值(1)和最大值(4)
  3. 必须检查已插入的值是否已插入(不知道如何动态执行此操作)

我红了很多文章,但那些不是动态创建的。 请帮我这样做

谢谢

【问题讨论】:

    标签: typescript angular8


    【解决方案1】:

    不太清楚你在追求什么,但我认为它看起来像这样......

    private buildSubGroup(question) {
      switch (question.qType) {
        case 2:
          return this.fb.group(
            question.answers.reduce((subGroup, answer) => {
              return Object.assign(subGroup, {[answer]: [false]});
            }, {}), {validators: [atLeastOneRequired()]} // validation rules here unclear? is at least 1 required?
          );
        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: [uniqueNumbersValidator()]}
          );
        case 1: // it's counter intuitive but these are actually the same structure due to how angular handles radio input
        case 4:
          return this.fb.group({answer: ['', [Validators.required]]});
        default:
          throw new Error('unhandled question type');
      }
    }
    
    this.surveyQuestionForm = this.fb.group(
      this.questions.reduce((group, question) => {
        return Object.assign(group, {['q' + question.qNo]: this.buildSubGroup(question)});
      }, {});
    );
    

    所以基本上,你把你的问题数组简化为一个对象,用 'q' 加上 qNo 作为键,值是取决于 qType 的子表单组......你还需要一些组级别的自定义验证器需要编写以确认每个数字只出现一次并且至少选择了一个,可能如下所示:

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

    模板绑​​定本身与您拥有它的方式完全不同,但这回答了如何以动态方式构建表单控件。您可以通过迭代 questions 数组并以与我在此处使用 switch 语句构建表单组类似的方式与 formGroupName 和 formControlName 指令以及 ngSwitch 指令适当地绑定来构建问题模板。

    【讨论】:

    • 非常感谢您的回复,实际上我有 4 种问题。这个问题是第 2 种类型。所以在模板中我想读取问题数组并检查问题类型(qType)并生成问题.在这个问题中,我必须检查 qType === 2 然后生成这个问题。你能帮我这样做吗?而 uniqueNumbersValidator() 必须只添加这种类型的问题。如果你愿意,我可以给你一个包含所有 4 种类型问题的数组。
    • 我需要查看完整的类型数组才能写出完整的答案,但这里的内容应该让您了解编写动态表单的样子
    • 我更新了问题并添加了所有内容。请帮助我
    • 我展示了如何为所有问题类型构建表单组。过去这是一个新问题。
    • 非常感谢 brayan,您能告诉我如何在模板中执行此操作吗?
    猜你喜欢
    • 2017-11-27
    • 2019-05-31
    • 1970-01-01
    • 2017-07-20
    • 2019-02-01
    • 2017-07-03
    • 2021-12-04
    • 2016-09-18
    相关资源
    最近更新 更多