如何在 angular 模板驱动表单模型中使用字段集表示数组
How to represent Array using fieldset in angular template driven form model
我有一个包含嵌套对象数组的表单。为了表示多级表单视图模型,我们使用 ngModelGroup 来映射父子关系。有没有一种方法可以使用类似于 ngModelGroup 的指令来表示数组?
以下是模型,
export class SurveyViewModel {
Survey: Survey;
QuestionAnswerSets: QuestionAnswerSet[];
}
export class Survey {
Id: string;
Name: string;
}
export class QuestionAnswerSet {
Question: Question;
Answers: Answer[];
}
下面是视图,
<form [formGroup]="surveyForm" (ngSubmit)="onFormSubmit(surveyForm)">
<div formGroupName="Survey">
<input type="hidden" name="Id" formControlName="Id">
<label>{{model.Survey.Name}}</label>
</div>
<div class='qa-set' formArrayName="QuestionAnswerSets">
<fieldset *ngFor="let questionAnswerSet of surveyForm.controls.QuestionAnswerSets.controls; index as setId;" [formGroupName]="setId">
<div formGroupName="Question">
<input type="hidden" name="Id" formControlName="Id">
<label>{{setId+1}}. </label>
<label>{{model.QuestionAnswerSets[setId].Question.Value}}</label>
</div>
<div class="row" formArrayName="Answers">
<div *ngFor="let answer of this.surveyForm.controls.QuestionAnswerSets.controls[setId].controls.Answers.controls; index as answerId;"
[formGroupName]="answerId">
<div class="col-12 col-sm-3" formGroupName="Answer">
<input type="hidden" name="Id" formControlName="Id">
<label>
<input type="radio" name="Value" formControlName="Value" /> {{model.QuestionAnswerSets[setId].Answers[answerId].Value}}
</label>
</div>
</div>
</div>
</fieldset>
</div>
<div class="row form-group">
<div class="col-12">
<button type="button" class="btn btn-primary float-right" type="submit">submit</button>
</div>
</div>
</form>
在阅读了很多关于嵌套模型模板驱动表单和官方 angular 文档的文章后,我可以说这不能使用模板驱动表单来完成,因为没有表示数组的指令。 (按照 fieldset 对带有 ngModelGroup 的对象的方式进行分组)
这可以通过 angular 带有 FormArrayName
的反应形式来完成
这是使用 FormArray 的方法
组件
import { Component, OnInit } from "@angular/core";
import {
Validators,
FormBuilder,
FormGroup,
FormControl,
FormArray
} from "@angular/forms";
@Component({
...
})
export class SurveyComponent implements OnInit {
public surveyForm: FormGroup;
constructor(protected formBuilder: FormBuilder) {}
ngOnInit() {
this.surveyForm = this.formBuilder.group({
Survey: new FormGroup({
Id: new FormControl("", Validators.required),
Name: new FormControl("", Validators.required)
}),
QuestionAnswerSets: new FormArray([])
});
}
initSet() {
return this.formBuilder.group({
Question: new FormControl("", Validators.required),
Answers: new FormArray([])
});
}
addSet() {
const questionAnswerSets = <FormArray>(
this.surveyForm.controls.QuestionAnswerSets
);
questionAnswerSets.push(this.initSet());
}
removeSet(setId: number) {
let questionAnswerSets = <FormArray>(
this.surveyForm.controls.QuestionAnswerSets
);
questionAnswerSets.removeAt(setId);
}
initAnswer() {
return this.formBuilder.group({
Answer: new FormControl("", Validators.required)
});
}
addAnswer(setId: number) {
const questionAnswerSets = <FormArray>(
this.surveyForm.controls.QuestionAnswerSets
);
const answer = <FormArray>(
questionAnswerSets.controls[setId]["controls"].Answers
);
answer.push(this.initAnswer());
}
removeAnswer(setId: number, answerId: number) {
const questionAnswerSets = <FormArray>(
this.surveyForm.controls.QuestionAnswerSets
);
const answer = <FormArray>(
questionAnswerSets.controls[setId]["controls"].Answers
);
answer.removeAt(answerId);
}
}
模板
<form [formGroup]="surveyForm" (ngSubmit)="saveForm(surveyForm.value)">
<div formArrayName="QuestionAnswerSets">
<fieldset *ngFor="let questionAnswerSet of surveyForm.controls.QuestionAnswerSets.controls; index as setId;" [formGroupName]="setId">
<input type="text" formControlName="Question" />
<div formArrayName="Answers">
<div class="ui-g-12" *ngFor="let answer of this.surveyForm.controls.QuestionAnswerSets.controls[setId].controls.Answers.controls; index as answerId;"
[formGroupName]="answerId">
<input type="text" formControlName="Answer" />
<button type="button" (click)="removeAnswer(setId, answerId)">Remove Answer</button>
</div>
</div>
<button type="button" (click)="addAnswer(setId)">Add Answer</button>
</fieldset>
</div>
<button type="button" (click)="addSet()">Add Set</button>
</form>
可能我错过了什么,但它会给你一个想法
您仍然可以将模板驱动表单与 ngModelGroup 结合使用来构建表单模板并迭代数组(以生成输入字段)。
ngModelGroup 内部的数据表示是一个对象。
要以数组形式访问 ngModelGroup 值,您可以这样做(例如在提交时):
submit(form: NgForm) {
console.log('form data', form.value);
// Convert ngModelGroup Object to Array
const resourcesFormGroup: AbstractControl = form.control.get('resources');
const resources: Resource[] = Object.keys(resourcesFormGroup.value).map(item => {
return resourcesFormGroup.value[item];
});
console.log('form data fixed', {
...form.value,
resources
});
}
这并不优雅,但有效:)
我有一个包含嵌套对象数组的表单。为了表示多级表单视图模型,我们使用 ngModelGroup 来映射父子关系。有没有一种方法可以使用类似于 ngModelGroup 的指令来表示数组?
以下是模型,
export class SurveyViewModel {
Survey: Survey;
QuestionAnswerSets: QuestionAnswerSet[];
}
export class Survey {
Id: string;
Name: string;
}
export class QuestionAnswerSet {
Question: Question;
Answers: Answer[];
}
下面是视图,
<form [formGroup]="surveyForm" (ngSubmit)="onFormSubmit(surveyForm)">
<div formGroupName="Survey">
<input type="hidden" name="Id" formControlName="Id">
<label>{{model.Survey.Name}}</label>
</div>
<div class='qa-set' formArrayName="QuestionAnswerSets">
<fieldset *ngFor="let questionAnswerSet of surveyForm.controls.QuestionAnswerSets.controls; index as setId;" [formGroupName]="setId">
<div formGroupName="Question">
<input type="hidden" name="Id" formControlName="Id">
<label>{{setId+1}}. </label>
<label>{{model.QuestionAnswerSets[setId].Question.Value}}</label>
</div>
<div class="row" formArrayName="Answers">
<div *ngFor="let answer of this.surveyForm.controls.QuestionAnswerSets.controls[setId].controls.Answers.controls; index as answerId;"
[formGroupName]="answerId">
<div class="col-12 col-sm-3" formGroupName="Answer">
<input type="hidden" name="Id" formControlName="Id">
<label>
<input type="radio" name="Value" formControlName="Value" /> {{model.QuestionAnswerSets[setId].Answers[answerId].Value}}
</label>
</div>
</div>
</div>
</fieldset>
</div>
<div class="row form-group">
<div class="col-12">
<button type="button" class="btn btn-primary float-right" type="submit">submit</button>
</div>
</div>
</form>
在阅读了很多关于嵌套模型模板驱动表单和官方 angular 文档的文章后,我可以说这不能使用模板驱动表单来完成,因为没有表示数组的指令。 (按照 fieldset 对带有 ngModelGroup 的对象的方式进行分组)
这可以通过 angular 带有 FormArrayName
的反应形式来完成这是使用 FormArray 的方法
组件
import { Component, OnInit } from "@angular/core";
import {
Validators,
FormBuilder,
FormGroup,
FormControl,
FormArray
} from "@angular/forms";
@Component({
...
})
export class SurveyComponent implements OnInit {
public surveyForm: FormGroup;
constructor(protected formBuilder: FormBuilder) {}
ngOnInit() {
this.surveyForm = this.formBuilder.group({
Survey: new FormGroup({
Id: new FormControl("", Validators.required),
Name: new FormControl("", Validators.required)
}),
QuestionAnswerSets: new FormArray([])
});
}
initSet() {
return this.formBuilder.group({
Question: new FormControl("", Validators.required),
Answers: new FormArray([])
});
}
addSet() {
const questionAnswerSets = <FormArray>(
this.surveyForm.controls.QuestionAnswerSets
);
questionAnswerSets.push(this.initSet());
}
removeSet(setId: number) {
let questionAnswerSets = <FormArray>(
this.surveyForm.controls.QuestionAnswerSets
);
questionAnswerSets.removeAt(setId);
}
initAnswer() {
return this.formBuilder.group({
Answer: new FormControl("", Validators.required)
});
}
addAnswer(setId: number) {
const questionAnswerSets = <FormArray>(
this.surveyForm.controls.QuestionAnswerSets
);
const answer = <FormArray>(
questionAnswerSets.controls[setId]["controls"].Answers
);
answer.push(this.initAnswer());
}
removeAnswer(setId: number, answerId: number) {
const questionAnswerSets = <FormArray>(
this.surveyForm.controls.QuestionAnswerSets
);
const answer = <FormArray>(
questionAnswerSets.controls[setId]["controls"].Answers
);
answer.removeAt(answerId);
}
}
模板
<form [formGroup]="surveyForm" (ngSubmit)="saveForm(surveyForm.value)">
<div formArrayName="QuestionAnswerSets">
<fieldset *ngFor="let questionAnswerSet of surveyForm.controls.QuestionAnswerSets.controls; index as setId;" [formGroupName]="setId">
<input type="text" formControlName="Question" />
<div formArrayName="Answers">
<div class="ui-g-12" *ngFor="let answer of this.surveyForm.controls.QuestionAnswerSets.controls[setId].controls.Answers.controls; index as answerId;"
[formGroupName]="answerId">
<input type="text" formControlName="Answer" />
<button type="button" (click)="removeAnswer(setId, answerId)">Remove Answer</button>
</div>
</div>
<button type="button" (click)="addAnswer(setId)">Add Answer</button>
</fieldset>
</div>
<button type="button" (click)="addSet()">Add Set</button>
</form>
可能我错过了什么,但它会给你一个想法
您仍然可以将模板驱动表单与 ngModelGroup 结合使用来构建表单模板并迭代数组(以生成输入字段)。
ngModelGroup 内部的数据表示是一个对象。
要以数组形式访问 ngModelGroup 值,您可以这样做(例如在提交时):
submit(form: NgForm) {
console.log('form data', form.value);
// Convert ngModelGroup Object to Array
const resourcesFormGroup: AbstractControl = form.control.get('resources');
const resources: Resource[] = Object.keys(resourcesFormGroup.value).map(item => {
return resourcesFormGroup.value[item];
});
console.log('form data fixed', {
...form.value,
resources
});
}
这并不优雅,但有效:)