6

Using Dynamic forms, I need to give users the ability to create forms fields dynamically. There needs to be a 'Add' button and when user clicks on this button, 4 input fields would be created.

I am able to create one field dynamically so far. Below is my code

In the HTML, I am using index to create the formControlName

<div class="row">
          <div class="col-xs-12">
            <div formArrayName="properties">

              <button class="btn btn-default btn-xs" type="button" (click)="onAddProperty()">Add</button>
              <div class="form-group" *ngFor="let propertyControl of searchForm.get('properties').controls; let i = index">
                <input type="text" class="form-control" [formControlName]="i">

                <!--       <input type="text" class="form-control" [formControlName]="'B'"+"i">
              <input type="text" class="form-control" [formControlName]="'C'"+"i">
              <input type="text" class="form-control" [formControlName]="'D'"+"i"> -->
              </div>
            </div>
          </div>
        </div>

and then in the component, pushing the control to the FormArray

searchForm: FormGroup;
onAddProperty() {
    const control = new FormControl(null);
    (<FormArray>this.searchForm.get('properties')).push(control);
  }

Now, I can click 'Add' button any number of times, and for every click one input field will be created.

However, instead of one input field, I need 4 inputs fields to be created for every click. I am not able to make out how to give each of these form fields unique formControlName. Right now, I am using index of the field which would be unique for 1 field, but wouldn't be so for 4 fields.

kayasa
  • 2,055
  • 8
  • 37
  • 63

2 Answers2

14

I think a simple for loop would do here. As for your template, I had some trouble understanding the code inside the comment (in template). In this case you don't need to do anything else than just declare the formControlName's with index inside your iteration of formArray, so something like this:

<div formArrayName="properties">
  <div *ngFor="let prop of searchForm.get('properties').controls; let i=index">
    <input type="text" class="form-control" [formControlName]="i">
  </div>
</div>

And then the loop that inserts 4 new input fields:

onAddProperty() {
  for(var i=1; i<=4; i++) {
    <FormArray>this.searchForm.get('properties').push(new FormControl());
  }
}

DEMO

AT82
  • 71,416
  • 24
  • 140
  • 167
  • Thank you very much. What if one of these 4 fields need to be a drop down? – kayasa Jun 12 '17 at 08:27
  • Well, this is so little information to go on. What would be the content for the dropdown? And how to determine which one should be the dropdown? :) – AT82 Jun 12 '17 at 08:30
  • Let's say the second field (of 4 fields) will always be a dropdown. It would just have 2 static values - 'Apples' and 'Oranges' – kayasa Jun 12 '17 at 08:32
  • Okay, let me think for a while, I'll get back to you with something, either I'm so stupid that I can't figure this one out, or then I'm extremely smart! :D :D I'll get back to you :) – AT82 Jun 12 '17 at 08:39
  • 2
    @kayasa, I couldn't really think of anything else, than building nested formgroups to the formarray. Hopefully this solution would work for you, even though it requires a bit more code and the form object is diffferent than before: http://plnkr.co/edit/HN8EO0WB0YsdIHFTC00f?p=preview – AT82 Jun 12 '17 at 10:02
1

did you see check this link Plunker

<form novalidate (ngSubmit)="onSubmit()" [formGroup]="users">
      <div formArrayName="data">
        <ng-container *ngFor="let user of fData.controls; index as i">
          <div [formGroupName]="i">
            <label>
              <span>Full name</span>
              <input type="text" placeholder="Name" formControlName="name">
            </label>
            <div class="error" *ngIf="user.get('name').touched && user.get('name').hasError('required')">
              Name is required
            </div>
            <div class="error" *ngIf="user.get('name').touched && user.get('name').hasError('minlength')">
              Minimum of 2 characters
            </div>
            <div formGroupName="account">
              <label>
                <span>Email address</span>
                <input type="email" placeholder="Email" formControlName="email">
              </label>
              <div
                class="error"
                *ngIf="user.get('account').get('email').hasError('required') && user.get('account').get('email').touched">
                Email is required
              </div>
              <label>
                <span>Confirm address</span>
                <input type="email" placeholder="Address" formControlName="confirm">
              </label>
              <div
                class="error"
                *ngIf="user.get('account').get('confirm').hasError('required') && user.get('account').get('confirm').touched">
                Confirming email is required
              </div>
            </div>
            <button type="submit" [disabled]="user.invalid">Sign up</button>
          </div>
        </ng-container>
      </div>
    </form>
paruvelly Vishwanath
  • 1,202
  • 3
  • 14
  • 30