使用 NgFor 的响应式表单

ReactiveForm using NgFor

我已经尝试解决这个问题一段时间了,但我被困住了。我的方法似乎效率低下且不正确。

我正在做的是,使用 *ngFor 生成我的表单值,我正在为答案和问题动态创建表单控件。

问题是,在提交时我需要有与问题相关的答案,这样我才能转到下一个屏幕。 *ngFor 生成的问题按选中的复选框排序,如果选中 = true;然后将问题冒泡到顶部。

问题是在提交时,pvqForm 传递了 formControls,我需要将答案与其关联的问题相关联。 FormControls 有一个前缀 {{i}} --> 索引,但是,这个索引在排序之后。所以索引 19 可能不是 question_id = '19'.

我在提交时试图实现的对象是:

{
   question_id: "#",
   EN: "Question - #",
   FR: "Question - #",
   answer: "",
   isSelected: true
}

我可以将所有问题保存在一个数组中,只需使用question_id来匹配问题。但是,我怎样才能实现匹配 question_id 连同答案一起?

*ngFor 开头的对象的形状为...

{
  question_id: "1",
  EN: "Question 1 - EN",
  FR: "Question 1 - FR",
  isSelected: true
},
{ 
  question_id: "2",
  EN: "Question 2 - EN",
  FR: "Question 2 - FR",
  isSelected: false
}

我的组件:

export class FpPVQ implements OnInit {
  private questions: any;
  private lang: string;
  private counter: number = 0;
  private checkedLimit: number = 5;
  private updateMode: boolean = false;
  private createMode: boolean = false;
  private deadlinePassed: boolean = false;
  private previousScreen: string = "";
  private flowA: boolean = false;
  private flowB: boolean = false;
  private flowC: boolean = false;
  private flowD: boolean = false;
  private pvqForm: FormGroup;
  private answer_0: FormControl;
  private answer_1: FormControl;
  private answer_2: FormControl;
  private answer_3: FormControl;
  private answer_4: FormControl;
  private answer_5: FormControl;
  private answer_6: FormControl;
  private answer_7: FormControl;
  private answer_8: FormControl;
  private answer_9: FormControl;
  private answer_10: FormControl;
  private answer_11: FormControl;
  private answer_12: FormControl;
  private answer_13: FormControl;
  private answer_14: FormControl;
  private answer_15: FormControl;
  private answer_16: FormControl;
  private answer_17: FormControl;
  private answer_18: FormControl;
  private answer_19: FormControl;
  private question_0: FormControl;
  private question_1: FormControl;
  private question_2: FormControl;
  private question_3: FormControl;
  private question_4: FormControl;
  private question_5: FormControl;
  private question_6: FormControl;
  private question_7: FormControl;
  private question_8: FormControl;
  private question_9: FormControl;
  private question_10: FormControl;
  private question_11: FormControl;
  private question_12: FormControl;
  private question_13: FormControl;
  private question_14: FormControl;
  private question_15: FormControl;
  private question_16: FormControl;
  private question_17: FormControl;
  private question_18: FormControl;
  private question_19: FormControl;


  private answerControlArr: Array<FormControl> = [];
  private questionsArr: Array<any> = [];



@ViewChild(DirtyModalComponent) public readonly dirtyModal: DirtyModalComponent;

  constructor(private _pvqStepUp: PVQStepUpService, private _langToggle: ErrorToggleService, private router: Router) { }

  ngOnInit() {
    this.lang = window['appdata'].apiUserLanguage;
    console.log('fpPVQ:: pvqStepUpData --> {}, ', this._pvqStepUp.data);
    if (this._pvqStepUp.data != null) {
      this.previousScreen = this._pvqStepUp.data.previousScreen;
      this.questions = this._pvqStepUp.data.pvqs;
      console.log('4176 FPVQ:: flow --> {}', this._pvqStepUp.data.flow);
      switch(this._pvqStepUp.data.flow){
        case "A": this.flowA = true; break;
        case "B": this.flowB = true; break;
        case "C": this.flowC = true; break;
        case "D": this.flowD = true; break;
      }
      this.questions.forEach(object => {
        this.questionsArr.push([object.question_EN, object.question_FR, object.answer]);
        console.log(object.question_id, object.EN, object.FR);
      })
      if (this._pvqStepUp.data.deadlinePassed)
        this.deadlinePassed = true;
    }

this.answer_0 = new FormControl('', Validators.required);
this.answer_1 = new FormControl('', Validators.required);
this.answer_2 = new FormControl('', Validators.required);
this.answer_3 = new FormControl('', Validators.required);
this.answer_4 = new FormControl('', Validators.required);
this.answer_5 = new FormControl('', Validators.required);
this.answer_6 = new FormControl('', Validators.required);
this.answer_7 = new FormControl('', Validators.required);
this.answer_8 = new FormControl('', Validators.required);
this.answer_9 = new FormControl('', Validators.required);
this.answer_10 = new FormControl('', Validators.required);
this.answer_11 = new FormControl('', Validators.required);
this.answer_12 = new FormControl('', Validators.required);
this.answer_13 = new FormControl('', Validators.required);
this.answer_14 = new FormControl('', Validators.required);
this.answer_15 = new FormControl('', Validators.required);
this.answer_16 = new FormControl('', Validators.required);
this.answer_17 = new FormControl('', Validators.required);
this.answer_18 = new FormControl('', Validators.required);
this.answer_19 = new FormControl('', Validators.required);

this.question_0 = new FormControl();
this.question_1 = new FormControl();
this.question_2 = new FormControl();
this.question_3 = new FormControl();
this.question_4 = new FormControl();
this.question_5 = new FormControl();
this.question_6 = new FormControl();
this.question_7 = new FormControl();
this.question_8 = new FormControl();
this.question_9 = new FormControl();
this.question_10 = new FormControl();
this.question_11 = new FormControl();
this.question_12 = new FormControl();
this.question_13 = new FormControl();
this.question_14 = new FormControl();
this.question_15 = new FormControl();
this.question_16 = new FormControl();
this.question_17 = new FormControl();
this.question_18 = new FormControl();
this.question_19 = new FormControl();

this.answerControlArr.push(this.answer_0);
this.answerControlArr.push(this.answer_1);
this.answerControlArr.push(this.answer_2);
this.answerControlArr.push(this.answer_3);
this.answerControlArr.push(this.answer_4);
this.answerControlArr.push(this.answer_5);
this.answerControlArr.push(this.answer_6);
this.answerControlArr.push(this.answer_7);
this.answerControlArr.push(this.answer_8);
this.answerControlArr.push(this.answer_9);
this.answerControlArr.push(this.answer_10);
this.answerControlArr.push(this.answer_11);
this.answerControlArr.push(this.answer_12);
this.answerControlArr.push(this.answer_13);
this.answerControlArr.push(this.answer_14);
this.answerControlArr.push(this.answer_15);
this.answerControlArr.push(this.answer_16);
this.answerControlArr.push(this.answer_17);
this.answerControlArr.push(this.answer_18);
this.answerControlArr.push(this.answer_19);

this.pvqForm = new FormGroup({
  answerControl0: this.answer_0,
  answerControl1: this.answer_1,
  answerControl2: this.answer_2,
  answerControl3: this.answer_3,
  answerControl4: this.answer_4,
  answerControl5: this.answer_5,
  answerControl6: this.answer_6,
  answerControl7: this.answer_7,
  answerControl8: this.answer_8,
  answerControl9: this.answer_9,
  answerControl10: this.answer_10,
  answerControl11: this.answer_11,
  answerControl12: this.answer_12,
  answerControl13: this.answer_13,
  answerControl14: this.answer_14,
  answerControl15: this.answer_15,
  answerControl16: this.answer_16,
  answerControl17: this.answer_17,
  answerControl18: this.answer_18,
  answerControl19: this.answer_19,
  questionControl0: this.question_0,
  questionControl1: this.question_1,
  questionControl2: this.question_2,
  questionControl3: this.question_3,
  questionControl4: this.question_4,
  questionControl5: this.question_5,
  questionControl6: this.question_6,
  questionControl7: this.question_7,
  questionControl8: this.question_8,
  questionControl9: this.question_9,
  questionControl10: this.question_10,
  questionControl11: this.question_11,
  questionControl12: this.question_12,
  questionControl13: this.question_13,
  questionControl14: this.question_14,
  questionControl15: this.question_15,
  questionControl16: this.question_16,
  questionControl17: this.question_17,
  questionControl18: this.question_18,
  questionControl19: this.question_19
});

    //Determine if Update or Create
    if (this._pvqStepUp.data.flow !== 'A' && this._pvqStepUp.data.flow != "B") {
      this.createMode = true;
      this.counter = 0;
    } else {
      this.updateMode = true;
      this.counter = 5;
    }

    this._langToggle.getLanguage().subscribe(
      lang => {
        this.lang = lang.toString();
      });
  }


  checkedState(event, checkBox) {
    if (event.target.checked === true) {
      if (this.counter < this.checkedLimit) {
        this.counter++;
      } else {
        event.target.checked = false;
      }
    } else if (this.counter > 0) {
      let index = event.target.name;
      //When clicking off the checkbox, set value to null
      this.answerControlArr[index].setValue(null);
      this.counter--;
    }
  }

  onSubmit(pvqForm: any) {
    console.log('4176-21 Submitted data --> {}', pvqForm);
    // console.log(pvqForm._value);
    Object.keys(pvqForm._value).map((key) => {
      console.log('4176-21 Object Key: ', key, ' Object Value: ', pvqForm._value[key]);
      // console.log('Question Controm name ' + pvqForm._value[key]);
      if(key.startsWith('questionControl')){
      }
      if(key.startsWith('answerControl')){
        let index = key.replace('answerControl', '');
        console.log('Index is: ' + index);
        console.log('Value is: ', pvqForm._value[key]);
      }
    })
  }

  cancel() {
    this.dirtyModal.show();
  }

  modalStay() {
    this.dirtyModal.hide();
  }

  modalLeave() {
    //Navigate Away to the previous screen
    // this.router.navigate([this.previousScreen]);
    location.assign(this.previousScreen);
  }

  isDisabled() {
    if (this.counter == 5) {
      //Enable if 5 Checkboxes are selected
      return false;
    } else {
      //Disable if 5 Checkboxes are not selected
      return true;
    }
  }

}

HTML:

<form [formGroup]="pvqForm" (ngSubmit)="onSubmit(pvqForm)" novalidate>
      <div *ngFor="let question of questions | sortBy: 'selected'; let i = index" class="row container-generic">
        <div class="col-md-8">
          <div class="container-input-checkbox">
            <label class="container-flex">
            <input formControlName='questionControl{{i}}' #checkBox class="pvq-create-checkbox" type="checkbox" name="{{i}}" (change)="checkedState($event, checkBox)" [checked]="question.selected"> 
            <div class="pvq-create-label">
              <div *ngIf="lang == 'en'">
                  <p aria-label="English Question">{{ question.EN }}</p>
              </div>
              <div *ngIf="lang == 'fr'">
                  <p aria-label="French Question">{{ question.FR }}</p>
              </div>
            </div>
          </label>
            <label [@hideShow]="checkBox.checked ? 'show' : 'hide'">Answer
            <input minlength=4 formControlName='answerControl{{i}}' type="textbox" name="{{i}}">
             <div *ngIf="!pvqForm.controls['answerControl' + i].valid && pvqForm.controls['answerControl' + i].touched" style="color: red;">
               Error here 
             </div>
          </label>
          </div>
        </div>
      </div>

您可以使用 Form Arrays 删除大量重复项。

这些可以使用 Form Builder

创建

我也把问题和答案放在一起了。

import { FormBuilder } from '@angular/forms'

...

ngOnInit() {
  this.questionGroups = this.fb.array(this.getQuestions().map(question => this.fb.group(question)));

  this.pvqForm = this.fb.group({
    questions: this.questionGroups
  });

  console.log(this.pvqForm);
}

getQuestions() {
  const questionControlArray = [];
  for (let i = 0; i < 20; i++) {
    questionControlArray.push({ 
      question: ['', Validators.required], 
      answer: ['']
    });
  }
  return questionControlArray;
}

然后它们将显示在视图中,如下所示:

<form [formGroup]="pvqForm" (ngSubmit)="submit(pvqForm)">
  <div [formArrayName]="'questions'">
    <div *ngFor="let question of questionGroups.controls; let i = index;" class="form-group">
      <div [formGroupName]="i">
        <label class="center-block">{{'question ' + i}}:
          <input formControlName="question" class="form-control"/> 
        </label>
        <label class="center-block">{{'answer ' + i}}:
          <input formControlName="answer" class="form-control"> 
        </label>
      </div>
    </div>
  </div>

  <button>Submit</button>
</form>