Reputation: 379
I need to present a set of questions fetched from an API, and having trouble displaying the form in the template, and getting the correct values of the user's response. The format of the APIs response is the following:
{
questions: [
{
text: 'Is this a question?',
id: 'question1',
answers: [
{ text: 'Yes', id: 'answer1' },
{ text: 'No!', id: 'answer2' },
{ text: 'Don't know?', id: 'answer3' }
]
}
]
}
I have created a form which looks like the following:
In the component
constructor(private fb: FormBuilder) {
this.questionsAnswersForm = this.fb.group({
answers: this.fb.array([])
});
}
this.initFormWithQAs()
initFormWithQAs(): void {
this.questions.map(() =>
(<FormArray>this.questionsAnswersForm.get('answers')).push(
this.addQuestionFormGroup()
)
);
}
addQuestionFormGroup(): FormGroup {
return this.fb.group({
questionId: [null, Validators.required],
answerId: [null, Validators.required]
});
}
In the template
<div formArrayName="answers" *ngFor="let q of questions">
<h5>{{ q.text }}</h5>
<form [formGroupName]="q.id" class="qa-list">
<label *ngFor="let answer of q.answers">
<input
type="radio"
[value]="answer.id"
[formControlName]="answer.id"
/>
<span>{{ answer.text }}</span>
</label>
</form>
</div>
The questionnaire renders on the screen with the correct text, but the radio buttons are not uniquely selected (working like checkboxes), the values on form submit are always null, and i am also getting the following error:
TypeError: Cannot create property 'validator' on string 'question1'
Thanks for the help in advance!
Upvotes: 0
Views: 200
Reputation: 830
I just built something for you to generate dynamic reactive form based on data from api
this is .ts file file
questions = [
{
text: 'Is this a question?',
id: 'question1',
answers: [
{ text: 'Yes', id: 'answer1' },
{ text: 'No!', id: 'answer2' },
{ text: 'Dont know?', id: 'answer3' }
]
}
]
questionsAnswersForm: FormGroup;
constructor(private fb: FormBuilder) {
this.questionsAnswersForm = this.fb.group({});
this.initFormWithQAs();
}
initFormWithQAs(): void {
this.questions.forEach((question) => {
const questionAnswersGroup = this.fb.group({});
question.answers.forEach(answer => {
questionAnswersGroup.addControl(answer.id, new FormControl(false));
});
this.questionsAnswersForm.addControl(question.id, questionAnswersGroup);
});
}
display() {
console.log(this.questionsAnswersForm.value);
}
// To add required custom validation
initFormWithQAs(): void {
this.questions.forEach((question) => {
const questionAnswersGroup = this.fb.group({});
questionAnswersGroup
.setValidators([function (control) {
if (!Object.values(control.value).reduce((a, b) => a || b)) {
return { required: true };
}
return null
}]);
question.answers.forEach(answer => {
questionAnswersGroup.addControl(answer.id, new FormControl(false));
});
this.questionsAnswersForm.addControl(question.id, questionAnswersGroup);
});
}
and this is the html template
<form [formGroup]="questionsAnswersForm">
<div [formGroupName]="q.id" *ngFor="let q of questions">
<h5>{{ q.text }}</h5>
<label *ngFor="let answer of q.answers">
<input type="radio" [value]="answer.id" [formControlName]="answer.id" />
<span>{{ answer.text }}</span>
</label>
</div>
<button (click)="display()">Display values</button>
</form>
Upvotes: 1