Angular dynamic formControlName generate with fromGroup
Complementary my comment, NOTE:you need add the validators (I can't see them in your code)
this.updateForm=new FormGroup({}) //<--create the formGroup
for(let formModule of this.keyArray){
this.updateForm.addcontrol(formModule.key,new FormControl(formModule.Value))
}
Moreover, if our objects in keyArray was like
{ "key" : "key_name" ,
"value" : "value" ,
"name" : "Key name" ,
validators:[Validators.required, Validators.email]
}
We can improve our loop
for(let formModule of this.keyArray){
this.updateForm.addcontrol(formModule.key,
new FormControl(formModule.Value,formModule.validators))
}
Well, if difficult that our object becomes from a service like I showed, but it's possible our services serve us object like:
{ "key" : "key_name" ,
"value" : "value" ,
"name" : "Key name" ,
validators:[{type:"required"},{type="min",args:3}]
}
Before make the loop we can use
this.keyArray.forEach(x=>
{
if (x.validators)
{
conts validators=[];
validators.forEach(v=>{
switch (v.type)
{
case "required":
validators.push(Validators.required);
break;
case "min":
validators.push(Validators.min(v.arg);
break;
...
}
})
x.validators=validators;
}
}
About to show the errors we must take account that our controls in a form is
updateForm.get(keyArray.key)
So, e.g.
<div class="col-lg-6" *ngFor="let keyArray of keyArray">
<mat-form-field>
<input type="text" [formControlName]="keyArray.key" matInput
[placeholder]="keyArray.name"
[ngClass]="{ 'is-invalid': submitted && updateForm.get(keyArray.key).errors }"
autocomplete="off" />
<mat-error *ngIf="submitted && updateForm.get(keyArray.key).hasError('required')">
{{keyArray.name}} is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
Monkey D. Luffy
A Web and Mobile App dev like to do trekking on Weekends, watch the Stars and learn about them every night and when I reach my place, I start with the various king of Anime as I'm beloved Otaku member :v.
Updated on June 04, 2022Comments
-
Monkey D. Luffy about 2 years
I have created a form which consist of JSON array and according to that, I am generating Validation,formControlName and generating output through formGroup.
this.ELEMENT_DATA_UPDATE = [ { first_name : 'abc', last_name : 'xyz', phone : 8888888888 } ];
Here, I am using Angular material so converted this key value pair to another array consists of
{"key" : "first_name" , "value" : "abc" , "name" : "First name :"}
This is when the input JSON array is fixed. But my project consists of data manipulation on a large scale in which input JSON array contents will change many times. There is no problem in generating UI modules, but when I try to apply Validation and forms modules to this dynamically generated contents, whole flow collapse ,
this is my code
var jsonArray : any = [{}]; export class UpdateContactFieldDialog { matcher = new MyErrorStateMatcher(); updateForm: FormGroup; formString : string = null; ELEMENT_DATA_UPDATE : any[] = []; keyArray : any[] = []; myJobFunctionControl = new FormControl(); optionsJobFunction: string[] = ['Operations', 'Production', 'Manufacturing']; myTitleControl = new FormControl(); optionsTitle: string[] = ['HR', 'Developer', 'Tester', 'MD', 'CEO', 'Director']; constructor(private formBuilder: FormBuilder,private dialogRef: MatDialogRef<AddContactFieldDialog> ) { } ngOnInit() { //dumy randomly geneated fields this.ELEMENT_DATA_UPDATE = [ { first_name : 'abc', last_name : 'xyz', job_function : 'Production', title : 'Developer', email : '[email protected]', phone : 7945612304 } ]; for (let obj of this.ELEMENT_DATA_UPDATE) { console.log("object length:", this.ELEMENT_DATA_UPDATE.length); for (let key in obj) { this.keyArray.push({'key' : key , 'value' : obj[key] , 'name': (key.charAt(0).toUpperCase() + key.substr(1).toLowerCase()).replace(/_/g, ' ')}); } break; } console.log(this.keyArray); console.log(this.ELEMENT_DATA_UPDATE[0]); for(let formModule of this.keyArray){ var keyData = formModule.key; if(this.formString != null && keyData == 'email' || keyData.includes('mail')){ this.formString = this.formString +''+keyData+':[this.ELEMENT_DATA_UPDATE[0].'+keyData +',[Validators.required,Validators.email]], '; } else if(this.formString != null && keyData == 'phone' || keyData.includes('number') || keyData.includes('no') || keyData.includes('num') ){ this.formString = this.formString +''+keyData+':[this.ELEMENT_DATA_UPDATE[0].'+keyData +',[Validators.required,Validators.minLength(10),Validators.maxLength(10),Validators.pattern("[0-9]*")]], '; } else if(this.formString == null && keyData != 'email' && keyData != 'phone'){ this.formString = ''+keyData+':[this.ELEMENT_DATA_UPDATE[0].'+keyData +',Validators.required], '; } else{ this.formString = this.formString + ''+keyData+':[this.ELEMENT_DATA_UPDATE[0].'+keyData +',Validators.required], '; } } console.log(this.formString); jsonArray = (this.formString); this.updateForm = this.formBuilder.group(jsonArray); } // convenience getter for easy access to form fields get f() { return this.updateForm.controls; } submitContact() { this.submitted = true; // stop here if form is invalid if (this.updateForm.valid) { // alert('SUCCESS!! :-)\n\n' + JSON.stringify(this.updateForm.value)) console.log(this.updateForm.value); this.dialogRef.close(); } else{ return; } } }
My code is generating following code as String
first_name: ['', Validators.required], last_name: ['', Validators.required], job_function: ['', [Validators.required]], title: ['', [Validators.required]], email: ['', [Validators.required, Validators.email]], phone : ['',[Validators.required, Validators.minLength(10), Validators.maxLength(10), Validators.pattern('[0-9 ]*')]]
I want this to be used inside of formGroup so i can dynamically generate formControls , assign them validation and values.
updateForm = this.formBuilder.group(jsonArray);
-
Eliseo over 5 yearsNot generate a string, make an empty FormGroup (myform=new FormGroup()) and for each keyArray use myForm.addcontrol (name,...) angular.io/api/forms/FormGroup#addcontrol
-
Monkey D. Luffy over 5 yearsCan you Elaborate? cause I have tried doing that. But your concept may be different. Suppose I have 5 documents and from which I'll fetch 5 seperate key's and need to apply Validation to those 5 keys and dynamically using for. SO how should i do that with your logic ? @Eliseo
-
-
Eliseo over 5 yearsI forgot {} in new FormGroup(..)
-
Monkey D. Luffy over 5 yearsThanks man. It worked for me. just added my validators to your code
this.updateForm.addcontrol(formModule.key,new FormControl(formModule.Value, Validators.required))
-
Monkey D. Luffy over 5 yearsIt worked well for scripting part but now generating bug at a front-end at <mat-error> and [ngClass] binding for f.keyArray.key
<div class="col-lg-6" *ngFor="let keyArray of keyArray"> <mat-form-field> <input type="text" [formControlName]="keyArray.key" matInput [placeholder]="keyArray.name" [ngClass]="{ 'is-invalid': submitted && f.keyArray.key.errors }" autocomplete="off" /><mat-error *ngIf="submitted && f.keyArray.key.hasError('required')"> {{keyArray.name}} is <strong>required</strong> </mat-error></mat-form-field></div>
apology for poor formating -
Eliseo over 5 yearsis NOT f.keyArray.key.errores, is
updateForm.get(keyArray.key).errors
, andupdateForm.get(keyArray.key).hasError('required')
-if your form is called updateForm- -
Monkey D. Luffy over 5 yearsYeah. it is but I am generating random errors depending upon variables passed to fromControlName at front-end(UI) and at angular (.ts). It works well with.ts but causing problem with UI part at formControlName and <mat-error> tag at keyArray.key where keyArray is array generated by backend which consist json data as
{ "key" : "key_name" , "value" : "value" , "name" : "Key name" }
-
Eliseo over 5 yearsI try to extends my answer, I hope this help you
-
Monkey D. Luffy over 5 yearsThanks, @Eliseo. This worked for me. I'll try to update your code in order to share working code.