0

I have form fields and need to add some more different fields when the user clicks on the Add button.If the user clicks on Add button, the new form is opening in a modal window where he can configure the name of the field, type and value). How do i add newly created dynamic elements to existing form.

I have tried using the following code but not adding the newly generated fields.
issuer.html

<dynamic-form [dataObject]="person"></dynamic-form>
<button type="submit" class="btn btn-info" (click)="addbtn();">ADD</button>


issuer.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'issuer-config',
  templateUrl: './issuer.html'
})


export class IssuerConfig implements OnInit {
  person: any = [];

  constructor( 

  ) {
    person = {
    lcid: {
        label: 'LCID:',
        value: '',
        type: 'text'
    }
   }
  }
 //Assume the values coming from modal window
  addbtn = function() {
    Object.assign(this.person, {
      ipa: {
        label: 'IP:',
        value: '',
        type: 'text'
    },
  });

  };
}

dynamicform.component.ts

import { Component, OnInit, Input } from '@angular/core';
import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms';

@Component({
    selector: 'dynamic-form',
    template: `
    <form novalidate (ngSubmit)="onSubmit(form.value)" [formGroup]="issuerConfigForm" class="form-horizontal">
      <div *ngFor="let prop of objectProps">
      <div class="form-group row">
        <label [attr.for]="prop" class="col-sm-2 control-label">{{prop.label}}</label>

        <div [ngSwitch]="prop.type" class="col-sm-4">
                <input *ngSwitchCase="'text'" 
                    [formControlName]="prop.key"
                    [id]="prop.key" [type]="prop.type" class="form-control">
        </div>
          </div>
      </div> 
            <button type="submit">Submit</button>
    </form>
  `
})
export class DynamicFormComponent implements OnInit {
    @Input() dataObject;
    issuerConfigForm: FormGroup;
    objectProps;

    constructor() {
    }

    ngOnInit() {
        // remap the API to be suitable for iterating over it
        this.objectProps =
            Object.keys(this.dataObject)
                .map(prop => {
                    return Object.assign({}, { key: prop }, this.dataObject[prop]);
                });

        // setup the form
        const formGroup = {};
        for (let prop of Object.keys(this.dataObject)) {
            formGroup[prop] = new FormControl(this.dataObject[prop].value || '');
        }
        this.issuerConfigForm = new FormGroup(formGroup);
    }
    onSubmit(form) {
        console.log(form);
    }
}
2
  • You have to send issuerConfigForm from issuer component as a input otherwise you have to notify to dynamic form to regenerate the formGroup by event. tThe issue is your code ngOnint wont call once you click the addBtn method Commented Jun 26, 2018 at 4:09
  • @Indrakumara, can u please tell where i can change the code. Commented Jun 26, 2018 at 4:14

2 Answers 2

1

You can follow my below example to render dynamic form:

export class AppComponent implements OnInit {
  fields = {
    name: {
      type: 'text',
      value: 12,
      label: 'Name'
    }
  }

  fieldProps = Object.keys(this.fields);
  form: FormGroup;
  formControls = {};
  constructor(private fb: FormBuilder) {

    this.fieldProps.forEach(prop => {
      this.formControls[prop] = [this.fields[prop].value];
    })
    this.form = this.fb.group(this.formControls);
    this.form.valueChanges.subscribe(v => console.log(v));
  }
  ngOnInit(): void {
  }
}
<form [formGroup]="form">
  <div *ngFor="let prop of fieldProps">
    <label>{{fields[prop].label}}</label>
    <div [ngSwitch]="fields[prop].type">
      <input *ngSwitchCase="'text'" [formControlName]="prop">
    </div>
  </div>
</form>

enter image description here


Finally, you should use @Output to emit the form.value to the <issuer component>. I think we should define the controls structure data more clearly to easy to understand and rendering.

Sign up to request clarification or add additional context in comments.

2 Comments

@Duong, thanks for your valuable answer. I am using 'fb.array' to adding new controller using your code and its working fine. suppose if i want to add one more different field, whether i need to push the elements in to array or clear the array and push it again?
@vishnu If you use my code like a new controller inside your form by using fb.array, when you update the fields I think you need to re-render form again.
0

issuer.html

<dynamic-form [objectProps]="objectProps" [formGroup]="issuerConfigForm"></dynamic-form>
<button type="submit" class="btn btn-info" (click)="addbtn();">ADD</button>

issuer.component.ts

    export class IssuerConfig {
  ngOnInit() {

  }
  person: any = [];
  objectProps=[];
  issuerConfigForm:FormGroup;

  constructor(

  ) {
    this.person = {
      lcid: {
        label: 'LCID:',
        value: '2',
        type: 'text'
      }
    };
    this.generateView();
  }
  //Assume the values coming from modal window
  addbtn = function () {
    Object.assign(this.person, {
      ipa: {
        label: 'IP:',
        value: '1',
        type: 'text'
      },
    });

    this.generateView();

  };

  generateView(){
      // remap the API to be suitable for iterating over it
      this.objectProps =
      Object.keys(this.person)
          .map(prop => {
              return Object.assign({}, { key: prop }, this.person[prop]);
          });

  // setup the form
  const formGroup = {};
  for (let prop of Object.keys(this.person)) {
      formGroup[prop] = new FormControl(this.person[prop].value || '');
  }
   this.issuerConfigForm = new FormGroup(formGroup);


  }
}

dynamicform.component.ts

@Component({
  selector: 'dynamic-form',
    template: `
    <form novalidate (ngSubmit)="onSubmit(form.value)" [formGroup]="formGroup" class="form-horizontal">
      <div *ngFor="let prop of objectProps">
      <div class="form-group row">
        <label [attr.for]="prop" class="col-sm-2 control-label">{{prop.label}}</label>

        <div [ngSwitch]="prop.type" class="col-sm-4">
                <input *ngSwitchCase="'text'" 
                    [formControlName]="prop.key"
                    [id]="prop.key" [type]="prop.type" class="form-control">
        </div>
          </div>
      </div> 
            <button type="submit">Submit</button>
    </form>
  `
})
export class DynamicFormComponent implements OnInit {
 @Input() formGroup;
 @Input() objectProps;
  constructor() { }

  ngOnInit() {
  }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.