如何使用Reactive表单在angular 2+中动态创建表单控制器

时间:2019-07-16 17:56:35

标签: typescript angular8

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

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

2)如何动态创建问题

3)如何动态添加验证

我使用角度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]]
     });
  }

这是问题预览  enter image description here

这是验证者必须使用的

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

我写了很多文章,但这些不是动态创建的。 请帮我做到这一点

谢谢

1 个答案:

答案 0 :(得分: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};
     }
   }

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