【问题标题】:ReactiveForm using NgFor使用 NgFor 的反应式表单
【发布时间】:2017-07-21 22:58:03
【问题描述】:

我一直试图弄清楚这一点,但我被困住了。我的方法似乎效率低下且不正确。

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

问题是,在提交时,我需要获得与问题相关的答案,这样我才能转到下一个屏幕。从 *ngFor 生成的问题按选中的复选框排序,如果 selected = 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>

【问题讨论】:

    标签: angular angular-reactive-forms


    【解决方案1】:

    您可以使用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>
    

    【讨论】:

    • 谢谢,但这不是我想要的。也许我可以将表单数组用于我的建议并想出一个解决方案。在那之前,还是迷路了。
    • 好的,所以您正在尝试将问题与答案关联起来,但不能因为顺序正在更改但 ID 不正确,对吗?您能否发布该组件的外观图片?恐怕我自己创建组件时缺少太多依赖项
    • 是的,如果有办法将问题或问题的 id 与答案分组,这样我就可以找出用户针对相应问题完成的答案。 ngFor 索引只是 barray 中问题数量的索引,当对问题进行排序时,问题 ID 不等于索引。我已经发布了组件代码。我可以稍后在家时截屏。
    • 您可以创建包含一个答案和一个问题的表单组,然后使用*ngFor 显示这些表单组,这样问题和答案将在响应中组合在一起。
    • 我在想类似的东西,不确定提交的表单会是什么样子。我回家的时候一定要试试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-22
    • 2019-01-04
    • 2020-05-11
    • 2020-04-28
    • 2019-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多