I have data consisting of array of person objects being returned from API for which I have to dynamically generate controls and display in Angular 12 app. The data returned is shown below.
{
"type": "Person",
"fields": [
{
"name": "fullName",
"label": "Full name",
"validation": {
"rules": {
"required": true,
"maxLength": 100
},
"errorMessages": {
"required": "Enter your full name",
"maxLength": "The full name must not exceed 100 characters"
}
}
},
{
"name": "phoneNumber",
"label": "Phone number",
"validation": {
"rules": {
"required": true,
"maxLength": 16
},
"errorMessages": {
"required": "Enter a valid phone number",
"maxLength": "The phone number must not exceed 16 characters"
}
}
},
{
"name": "email",
"label": "Email",
"validation": {
"rules": {
"required": true,
"format": "^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$"
},
"errorMessages": {
"required": "Enter a valid email address",
"format": "The email address must be valid"
}
}
}
],
"values": [
{
"id": 1,
"fullName": null,
"phoneNumber": null,
"email": null
},
{
"id": 2,
"fullName": "ytrytrytr",
"phoneNumber": null,
"email": null
},
{
"id": 3,
"fullName": "test",
"phoneNumber": "2353535",
"email": "dfdw@ww.com"
}
]
}
The code in my component.ts file to fetch the data and create form array and also form groups within that form array is shown below.
form!: FormArray;
personFields!: any;
personValues: any;
ngOnInit() {
this.personService.getData()
.subscribe((res: FormObject) => {
this.personFields = res.fields;
this.personValues = res.values;
this.form = new FormArray(this.personValues.map((value:
any)=>this.createPersonData(value)));
});
}
createPersonData(person: any) {
let personFormGroup = new FormGroup({});
let validationsArray = [];
this.personFields.forEach(formField => {
validationsArray = [];
if(formField.validation.rules.required) {
validationsArray.push(Validators.required);
}
if(formField.validation.rules.maxLength) {
validationsArray.push(Validators.maxLength(formField.validation.rules.maxLength));
}
if(formField.validation.rules.format) {
validationsArray.push(Validators.pattern(formField.validation.rules.format));
}
let formFieldValue = person[formField.name] ? person[formField.name] : null;
personFormGroup.addControl(formField.name, new FormControl(formFieldValue,
validationsArray));
});
return personFormGroup;
}
Now, I am binding to the template html file as shown below, lib-input and lib-show-errors are components which I have in an angular library which I am using in this app.
<form *ngIf="form" [formGroup]="form">
<div *ngFor="let ohFormGroup of form.controls;let i=index">
<div [formGroup]="ohFormGroup">
<ng-container *ngFor="let formField of ohFormGroup.controls;">
<div>
<div class="label">{{formField.label}}</div>
<lib-input [formControlName]="formField.name">
</lib-input>
</div>
<lib-show-errors *ngIf="isSubmitted && ohFormGroup.controls[formField.name].errors"
[formField]="ohFormGroup.controls[formField.name]"
[errorMessages]="formField.validation.errorMessages">
</lib-show-errors>
</ng-container>
</div>
</div>
</form>
I need to display controls corresponding to person objects returned in the values array in the JSON. For example if values array has 4 objects, I need to display four sets of Full Name, Phone Number and Email controls which are part of fields array in JSON. If user wants to add a 5th person by clicking a button, I should generate a form group for those 3 controls dynamically and display it and then on submitting the form I need to post all 5 objects to the API POST end point. That is my requirement.
I am facing errors with above template. They are
Type 'FormArray' is missing the following properties from type 'FormGroup': registerControl, addControl, removeControl for the line <form *ngIf="form" [formGroup]="form">
Type 'AbstractControl' is missing the following properties from type 'FormGroup': controls, registerControl, addControl, removeControl, and 3 more for the line <div [formGroup]="ohFormGroup">
Property 'controls' does not exist on type 'AbstractControl' for the line <ng-container *ngFor="let formField of ohFormGroup.controls;">
I don't know what exactly is causing above issues. Please help me out with this.
FormArray
s in your code – pixelbitsgetFormArray() { return myFormArray as FormArray }
– Will Alexander