Angular dynamic formControlName generate with fromGroup

11,970

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>
Share:
11,970
Monkey D. Luffy
Author by

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, 2022

Comments

  • Monkey D. Luffy
    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
      Eliseo over 5 years
      Not 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
      Monkey D. Luffy over 5 years
      Can 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
    Eliseo over 5 years
    I forgot {} in new FormGroup(..)
  • Monkey D. Luffy
    Monkey D. Luffy over 5 years
    Thanks 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
    Monkey D. Luffy over 5 years
    It 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
    Eliseo over 5 years
    is NOT f.keyArray.key.errores, is updateForm.get(keyArray.key).errors, and updateForm.get(keyArray.key).hasError('required') -if your form is called updateForm-
  • Monkey D. Luffy
    Monkey D. Luffy over 5 years
    Yeah. 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
    Eliseo over 5 years
    I try to extends my answer, I hope this help you
  • Monkey D. Luffy
    Monkey D. Luffy over 5 years
    Thanks, @Eliseo. This worked for me. I'll try to update your code in order to share working code.