基于 json 文件创建动态表单(json 文件可以在第一次创建表单后通过单击按钮更改)
Create dynamic form based on json file (json file can be changed by button click after first creation of form)
我正在尝试创建一个基于 https://angular.io/guide/dynamic-form 的动态表单。我正在使用 json 文件来创建动态表单。我有 2 个 json 文件(sbb.json,gx.json)。当我第一次从 json 文件中读取并创建表单时,它工作得很好。但是我有一个按钮 (Sbb) 可以将文件从 gx.json 更改为 sbb.json 。但是当我点击它时,它给了我以下错误。
ERROR TypeError: "this.form.controls[this.question.key] is undefined
但是当我单击按钮 "Gx" 时,它又正确地创建了表单,没有出现错误。
代码:
app.component.ts:
import { Component } from '@angular/core';
import SbbData from './sbb.json';
import GxData from './gx.json';
@Component({
selector: 'app-root',
template: `
<div>
<button type="button" (click)="callSbb()">SBB</button>
<button type="button" (click)="callGx()">GX</button>
<app-dynamic-form [questions]="questions"></app-dynamic-form>
</div>
`,
providers: []
})
export class AppComponent{
questions: any[];
constructor() {
this.questions = GxData;
}
callGx() {
this.questions = GxData;
}
callSbb() {
this.questions = SbbData;
}
}
动态表单组件:
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { QuestionControlService } from '../question-control.service';
@Component({
selector: 'app-dynamic-form',
templateUrl: './dynamic-form.component.html',
providers: [QuestionControlService]
})
export class DynamicFormComponent implements OnInit {
@Input() questions: any[] = [];
form: FormGroup;
payLoad = '';
constructor(private qcs: QuestionControlService) { }
ngOnInit() {
this.form = this.qcs.toFormGroup(this.questions);
}
onSubmit() {
this.payLoad = JSON.stringify(this.form.value);
}
}
动态形式-component.html:
<form (ngSubmit)="onSubmit()" [formGroup]="form">
<div *ngFor="let question of questions" class="form-row">
<app-question [question]="question" [form]="form"></app-question>
</div>
<div class="form-row">
<button type="submit" [disabled]="!form.valid">Save</button>
</div>
</form>
问题-control.service:
import { Injectable } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Injectable()
export class QuestionControlService {
constructor() { }
toFormGroup(questions: any[]) {
let group: any = {};
questions.forEach(question => {
group[question.key] = question.required ? new FormControl(question.value || '', Validators.required)
: new FormControl(question.value || '');
});
return new FormGroup(group);
}
}
动态表单问题组件:
import { Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
@Component({
selector: 'app-question',
templateUrl: './dynamic-form-question.component.html'
})
export class DynamicFormQuestionComponent {
@Input() question: any;
@Input() form: FormGroup;
get isValid() { return this.form.controls[this.question.key].valid; }
}
动态表单问题component.html:
<div [formGroup]="form">
<div [ngSwitch]="question.controlType" class="checkbox_wrapper">
<input *ngSwitchCase="'textbox'" [formControlName]="question.key" [id]="question.key" [type]="question.type" name="question.name">
<label [attr.for]="question.key">{{question.label}}</label>
<div *ngIf="question.child =='dropdown'" [formGroupName]="question.key">
<select [id]="question.key2" >
<option *ngFor="let opt of question.options" [attr.value]="opt.key" [attr.selected]="opt.select">{{opt.value}}</option>
</select>
</div>
<select [id]="question.key" *ngSwitchCase="'dropdown'" [formControlName]="question.key" >
<option *ngFor="let opt of question.options" [attr.value]="opt.key" [attr.selected]="opt.select">{{opt.value}}</option>
</select>
<!-- <label [attr.for]="question.key">{{question.label}}</label> -->
</div>
<div class="errorMessage" *ngIf="!isValid">{{question.label}} is required</div>
</div>
为了解决这个问题,我在 dynamic-form 组件中添加了 ngOnChanges() 方法。
import { Component, Input, OnInit, SimpleChanges } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { QuestionControlService } from '../question-control.service';
@Component({
selector: 'app-dynamic-form',
templateUrl: './dynamic-form.component.html',
providers: [QuestionControlService]
})
export class DynamicFormComponent implements OnInit {
@Input() questions: any[] = [];
form: FormGroup;
payLoad = '';
//newly added function
ngOnChanges(changes: SimpleChanges) {
for (let propName in changes) {
let change = changes[propName];
// let curVal = JSON.stringify(change.currentValue);
// let prevVal = JSON.stringify(change.previousValue);
if (propName === 'questions') {
this.form = this.qcs.toFormGroup(this.questions);
}
}
}
constructor(private qcs: QuestionControlService) { }
ngOnInit() {
this.form = this.qcs.toFormGroup(this.questions);
}
onSubmit() {
this.payLoad = JSON.stringify(this.form.value);
console.log(JSON.parse(this.payLoad));
}
}
我正在尝试创建一个基于 https://angular.io/guide/dynamic-form 的动态表单。我正在使用 json 文件来创建动态表单。我有 2 个 json 文件(sbb.json,gx.json)。当我第一次从 json 文件中读取并创建表单时,它工作得很好。但是我有一个按钮 (Sbb) 可以将文件从 gx.json 更改为 sbb.json 。但是当我点击它时,它给了我以下错误。
ERROR TypeError: "this.form.controls[this.question.key] is undefined
但是当我单击按钮 "Gx" 时,它又正确地创建了表单,没有出现错误。
代码:
app.component.ts:
import { Component } from '@angular/core';
import SbbData from './sbb.json';
import GxData from './gx.json';
@Component({
selector: 'app-root',
template: `
<div>
<button type="button" (click)="callSbb()">SBB</button>
<button type="button" (click)="callGx()">GX</button>
<app-dynamic-form [questions]="questions"></app-dynamic-form>
</div>
`,
providers: []
})
export class AppComponent{
questions: any[];
constructor() {
this.questions = GxData;
}
callGx() {
this.questions = GxData;
}
callSbb() {
this.questions = SbbData;
}
}
动态表单组件:
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { QuestionControlService } from '../question-control.service';
@Component({
selector: 'app-dynamic-form',
templateUrl: './dynamic-form.component.html',
providers: [QuestionControlService]
})
export class DynamicFormComponent implements OnInit {
@Input() questions: any[] = [];
form: FormGroup;
payLoad = '';
constructor(private qcs: QuestionControlService) { }
ngOnInit() {
this.form = this.qcs.toFormGroup(this.questions);
}
onSubmit() {
this.payLoad = JSON.stringify(this.form.value);
}
}
动态形式-component.html:
<form (ngSubmit)="onSubmit()" [formGroup]="form">
<div *ngFor="let question of questions" class="form-row">
<app-question [question]="question" [form]="form"></app-question>
</div>
<div class="form-row">
<button type="submit" [disabled]="!form.valid">Save</button>
</div>
</form>
问题-control.service:
import { Injectable } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Injectable()
export class QuestionControlService {
constructor() { }
toFormGroup(questions: any[]) {
let group: any = {};
questions.forEach(question => {
group[question.key] = question.required ? new FormControl(question.value || '', Validators.required)
: new FormControl(question.value || '');
});
return new FormGroup(group);
}
}
动态表单问题组件:
import { Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
@Component({
selector: 'app-question',
templateUrl: './dynamic-form-question.component.html'
})
export class DynamicFormQuestionComponent {
@Input() question: any;
@Input() form: FormGroup;
get isValid() { return this.form.controls[this.question.key].valid; }
}
动态表单问题component.html:
<div [formGroup]="form">
<div [ngSwitch]="question.controlType" class="checkbox_wrapper">
<input *ngSwitchCase="'textbox'" [formControlName]="question.key" [id]="question.key" [type]="question.type" name="question.name">
<label [attr.for]="question.key">{{question.label}}</label>
<div *ngIf="question.child =='dropdown'" [formGroupName]="question.key">
<select [id]="question.key2" >
<option *ngFor="let opt of question.options" [attr.value]="opt.key" [attr.selected]="opt.select">{{opt.value}}</option>
</select>
</div>
<select [id]="question.key" *ngSwitchCase="'dropdown'" [formControlName]="question.key" >
<option *ngFor="let opt of question.options" [attr.value]="opt.key" [attr.selected]="opt.select">{{opt.value}}</option>
</select>
<!-- <label [attr.for]="question.key">{{question.label}}</label> -->
</div>
<div class="errorMessage" *ngIf="!isValid">{{question.label}} is required</div>
</div>
为了解决这个问题,我在 dynamic-form 组件中添加了 ngOnChanges() 方法。
import { Component, Input, OnInit, SimpleChanges } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { QuestionControlService } from '../question-control.service';
@Component({
selector: 'app-dynamic-form',
templateUrl: './dynamic-form.component.html',
providers: [QuestionControlService]
})
export class DynamicFormComponent implements OnInit {
@Input() questions: any[] = [];
form: FormGroup;
payLoad = '';
//newly added function
ngOnChanges(changes: SimpleChanges) {
for (let propName in changes) {
let change = changes[propName];
// let curVal = JSON.stringify(change.currentValue);
// let prevVal = JSON.stringify(change.previousValue);
if (propName === 'questions') {
this.form = this.qcs.toFormGroup(this.questions);
}
}
}
constructor(private qcs: QuestionControlService) { }
ngOnInit() {
this.form = this.qcs.toFormGroup(this.questions);
}
onSubmit() {
this.payLoad = JSON.stringify(this.form.value);
console.log(JSON.parse(this.payLoad));
}
}