1

I was trying to accomplish dynamic duplication using the FormArray but I just couldn't do it. Please check the form on JSFiddle.

component.html

<div class="form-group">
  <div formArrayName="nqCoordinators">
    <button class="col-md-offset-1 col-md-1 btn btn-default" type="button">
       Add Coordinator
    </button>
    <div class="form-group" [ngClass]="{'has-error': (agencyForm.get('nqCoordinators').touched || agencyForm.get('nqCoordinators').dirty) && !agencyForm.get('nqCoordinators').valid}"
         *ngFor="let nqCoordinator of nqCoordinators.controls; let i=index">
      <label class="col-md-2 control-label" [attr.for]="i">Coordinator</label>
      <div class="col-md-8">
        <input class="form-control" id="i" type="text" placeholder="NQ Coordinator" formControlName="i" />
      </div>               
    </div>
  </div>
</div>

component.ts

import {
  Component,
  OnInit
}
from '@angular/core';
import {
  FormGroup,
  FormControl,
  FormBuilder,
  Validators,
  FormArray
}
from '@angular/forms';
import {
  ActivatedRoute,
  Router
}
from '@angular/router';
import {
  Subscription
}
from 'rxjs/Subscription';


@Component({
  templateUrl: './newq.component.html'
})
export class CreateNewQComponent implements OnInit {
  pageTitle: string;

  agencyForm: FormGroup;


  private sub: Subscription;
  get nqCoordinators(): FormArray {
     return <FormArray>this.agencyForm.get('nqCoordinators');
  }

  constructor(private route: ActivatedRoute, private fb: FormBuilder, private router: Router) {}

  //myOptions: IMultiSelectOption[] = [
  //    { id: 1, name: 'Option 1' },
  //    { id: 2, name: 'Option 2' },
  //];

  ngOnInit(): void {
      this.agencyForm = this.fb.group({
        nqCoordinators: this.fb.array([]),
        //qAdvisors: '',
        nq1: '',
        nq2: '',
        nq3: '',
        nq4: '',
        nqCoordinators: this.fb.array([]),
        nqStartDate: ''        
      });

      this.agencyForm.controls['salesRep'].valueChanges
          .subscribe((selectedOptions) => {
              // changes
          });
      this.sub = this.route.params.subscribe(
        params => {
          let id = +params['id'];
          if (id === 0)
            this.pageTitle = 'Add Q';
          else
            this.pageTitle = 'Edit Q';
        }
      );

    }

  add() {
    console.log(this.newQForm);
    console.log('Saved: ' + JSON.stringify(this.newQForm));
  }

  addAgency() {
    console.log(this.newQForm);
    console.log('Saved: ' + JSON.stringify(this.newQForm));
  }

  backBtnClick() {
    this.router.navigate(['/newq']);
  }
}
4
  • what do you mean with duplicate controls? What exactly is the problem, it's unclear? What is current behavior and what is expected behavior? Commented Jun 2, 2017 at 7:50
  • I was trying to dynamically duplicate textbox field for the Coordinator(If you was able to see in the JSFiddle) and it wont work. Commented Jun 2, 2017 at 14:23
  • I guess you mean to add more coordinators in the array? I guessed it was that, have to just make sure :) I'll take a look at your code and let's see if we can figure this one out. Commented Jun 2, 2017 at 14:25
  • Why do you have two forms? Other nested? You should really simplify your fiddle to showcase JUST the problem you have, not whole form... Commented Jun 2, 2017 at 14:36

1 Answer 1

2

You have a lot of code there, so here is a simpler example.

First of all, you have a nested <form> tag. That won't just work. Instead you should have just one main [formGroup] (with the form tag) in template. The rest in template should be formControlName's. FormArrayName's and nested FormGroupName's.

So here would be the build of the form, where we have one coordinator initially set:

this.agencyForm = this.fb.group({
  agencyName: [''],
  nqCoordinators: this.fb.array([
    this.initNqCoordinators() // we'll use the same function for adding new
  ])
});

initNqCoordinators() {
  return this.fb.group({
    // here add all your form controls needed for your coordinator
    whatever_form_control: ['']
  })
}

and here when you template click to add a new coordinator, it would look like this:

addCoordinator() {
  // our formarray with coordinators
  const control = <FormArray>this.agencyForm.controls['nqCoordinators'];
  // we call function to push a new formgroup to the array
  control.push(this.initNqCoordinators())
}

Then your template would look like this:

<form [formGroup]="agencyForm" (ngSubmit)="submit(agencyForm.value)">
  <label>Agency Name: </label>
  <input formControlName="agencyName"/><br><br>
  <button (click)="addCoordinator()">Add Coordinator</button><br>

  <div formArrayName="nqCoordinators">
     <div *ngFor="let child of agencyForm.controls.nqCoordinators.controls; let i = index" >
        <div formGroupName="{{i}}">
           <label>Whatever Coordinator formControl-name</label>
           <input formControlName="whatever_form_control" /><br><br>
        </div>
     </div>
  </div>
  <button type="submit">Submit</button>
</form>

A DEMO with the above.

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

2 Comments

Thanks a lot for the reply man! you made it look much easier. I appreciate your help!!
No problem! I know it can be confusing in the beginning. I scratched my head for a while before I wrapped my head around how reactive forms work :) Glad to hear it was helpful.

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.