I'm trying to generate form with data from api, I did everithing how it is writen in documentation: https://angular.io/guide/dynamic-form
andit works with array of question, but when questions coming from api it does'n work, I get this error. I changed a code according to this answer: https://stackoverflow.com/a/48391041 but it still doesn't work. Can you help me out ? :)
DynamicFormQuestionComponent.html:9 ERROR Error: Cannot find control
with name: 'previousMessage'
DynamicFormQuestionComponent.html:9 ERROR CONTEXT
DebugContext_ {view: {…}, nodeIndex: 3, nodeDef: {…}, elDef: {…}, elView: {…}}
question.component.html
<app-dynamic-form [questions]="(questions | async)"></app-dynamic-form>
question.component.ts
import { Component, OnInit } from '@angular/core';
import { QuestionService } from '../../question/question.service';
import { QuestionBase } from '../../question/question-base';
import { Observable } from 'rxjs/Observable';
@Component({
selector: 'app-qna',
templateUrl: './qna.component.html',
styleUrls: ['./qna.component.scss'],
providers: [QuestionService]
})
export class QnaComponent implements OnInit {
questions: Observable<any>;
constructor(private questionService: QuestionService) {
this.questions = this.questionService.getQuest()
}
ngOnInit() {
}
}
dynamic-form.component.ts
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { QuestionBase } from '../question-base';
import { QuestionControlService } from '../question-control.service';
@Component({
selector: 'app-dynamic-form',
templateUrl: './dynamic-form.component.html',
styleUrls: ['./dynamic-form.component.scss'],
providers: [QuestionControlService]
})
export class DynamicFormComponent implements OnInit {
private _questions = [];
@Input()
set questions(value: any[]) {
this._questions = value || [];
}
get questions(): any[] {
return this._questions;
}
form: FormGroup;
payLoad = '';
constructor(private qcs: QuestionControlService) { }
ngOnInit() {
this.form = this.qcs.toFormGroup(this.questions);
}
onSubmit() {
this.payLoad = JSON.stringify(this.form.value);
}
}
dynamic-form-question.component.html
<div class="form-group" [formGroup]="form">
<label [attr.for]="question.key">{{question.label}}</label>
<div [ngSwitch]="question.controlType">
<input class="form-control" *ngSwitchCase="'textbox'" [formControlName]="question.key"
[id]="question.key" [type]="question.type">
<select size="2" class="form-control" [id]="question.key" *ngSwitchCase="'dropdown'" [formControlName]="question.key">
<option *ngFor="let opt of question.options" [value]="opt.key">{{opt.value}}</option>
</select>
<input class="form-control" *ngSwitchCase="'date'" [formControlName]="question.key"
[id]="question.key" [type]="question.type">
<input class="form-control" *ngSwitchCase="'number'" [formControlName]="question.key"
[id]="question.key" [type]="question.type">
<textarea class="form-control" *ngSwitchCase="'textarea'" [formControlName]="question.key"
[id]="question.key"></textarea>
</div>
<div class="errorMessage" *ngIf="!isValid">{{question.label}} is required</div>
</div>
dynamic-form-question.component.ts
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { QuestionBase } from '../question-base';
@Component({
selector: 'app-dynamic-form-question',
templateUrl: './dynamic-form-question.component.html',
styleUrls: ['./dynamic-form-question.component.scss']
})
export class DynamicFormQuestionComponent {
@Input() question: QuestionBase<any>;
@Input() form: FormGroup;
get isValid() { return this.form.controls[this.question.key]
? this.form.controls[this.question.key].valid : true; }
}
question.service.ts
import { Injectable } from '@angular/core';
import { QuestionDropdown } from './question-dropdown';
import { QuestionBase } from './question-base';
import { QuestionTextbox } from './question-textbox';
import { QuestionDate } from './question-date';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
@Injectable()
export class QuestionService {
url = '';
questions: QuestionBase<any>[];
constructor(private http: HttpClient) { }
getQuest(): Observable<QuestionBase<any>[]>{
this.url = `http://localhost:3000/`;
return this.http.get(this.url, { withCredentials: true })
.map((questionMetadata) => this.metadataToQuestions(questionMetadata))
.map(questions => questions.sort((a, b) => a.order - b.order))
}
private metadataToQuestions(questionMetadata) {
console.log(questionMetadata['QnA'])
return questionMetadata['QnA'].map(this.toQuestion)
}
private toQuestion(elementData) {
let inputs = {
'textarea': QuestionTextbox,
'date': QuestionDate,
'dropdown': QuestionDropdown,
'number': QuestionTextbox,
'textbox': QuestionTextbox
}
let element = elementData.type
//that works :)
return new (inputs[element])({...elementData})
}