使用 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>
我已经尝试解决这个问题一段时间了,但我被困住了。我的方法似乎效率低下且不正确。
我正在做的是,使用 *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>