Angular FormArray: referencing dynamically added FormControl in template
Asked Answered
A

3

5

I am working on Angular Reactive forms, I have added a couple of FormControl into FormArray dynamically, but I am getting issue to reference those FormControls in my template while binding them with formControlName. In template I assigned loop index variable "i" to formControlName but its not working. I get "No value accessor for form control with path" by binding controls with formControlName. here is my component class code:

export class Control {
  constructor(public controlType?: string, public label?: string, public required?: boolean, public placeholder?: string,
    public options?: string[], public value?: string) { }
}

export class FormComponent implements OnInit {
  reviewForm: FormGroup;

  constructor(public formService: FormService, public dialog: MdDialog) { }


  selectedControl: any = null;
  label: string;

  ngOnInit() {
    this.reviewForm = new FormGroup({
      'controlArray': new FormArray([
      ])
    });
  }

  addControl() {
    const myControl: Control = new Control(this.selectedControl.name, this.label, this.isRequired,
      this.selectedControl.attributes.value, this.selectedControl.attributes.options, 'null');
    var control: FormControl = new FormControl(myControl);
    (<FormArray>this.reviewForm.get('controlArray')).push(control);
  }

}

And it is my component's template:

<form [formGroup]="reviewForm" (ngSubmit)="onSubmit()">
  <div class="example-label">
    <span class='block'>    
              <span *ngIf="selectedForm">
                      <h2 class="example-heading">{{displayForm}} </h2>
              </span>
    <div formArrayName="controlArray">
      <div *ngFor="let control of reviewForm.get('controlArray').controls; let i = index">
        <table>
          <tr>
            <span *ngIf="control.value">
                    <td> 
                      <label>{{control.value.label}}</label>                           
            </td>
            <td><span *ngIf="control.value.controlType == 'select'">                
                      <md-select placeholder="{{control.value.label}}" [formControlName]="i" >
                        <md-option *ngFor="let option of control.value.options; let i=index" 
                        [value]="option">{{control.value.options[i]}}</md-option>                  
                      </md-select>
                    </span></td>
            <td> <span *ngIf="control.value.controlType == 'text'">
              <md-form-field class="example-full-width">
                <input mdInput type="text" placeholder="{{control.value.placeholder}}" [formControlName]="i" >
              </md-form-field>  
          </span></td>
            <td> <span *ngIf="control.value.controlType == 'radio'">
              <md-radio-group>
                      <span *ngFor="let option of control.value.options">
                        <md-radio-button name="gender" value="{{option}}" [formControlName]="i" >{{option}} </md-radio-button>
                      </span>
              </md-radio-group>
              </span>
            </td>
            <td> <span *ngIf="control.value.controlType == 'checkbox'">
                      <md-checkbox value="{{control.value.controlType}}" [formControlName]="i" > </md-checkbox>
                    </span></td>

            <td> <span *ngIf="control.value.controlType == 'textarea'">
                      <textarea name="Comment" id="" cols="30" rows="10" [formControlName]="i" ></textarea>  
                    </span></td>

            <td> <span *ngIf="control.value.controlType == 'button'">
                        <button md-raised-button value="{{control.value}}" [formControlName]="i" >Button</button>  
                    </span> </td>
            </span>
          </tr>
        </table>
      </div>
    </div>
    </span>
  </div>
</form>

In my component class I only have FormArray in FormGroup. In addControl function I made a custom control and pass this control as a first parameter to a FormControl. Afterwards I push this FormControl into my FormArray. Please help, in template How do I associate formControlName to FormControls. Thanks

Anna answered 6/12, 2017 at 13:17 Comment(14)
*ngIf="control.value[formControlName]=" i "" what's this syntax?Stumer
Sorry, it was a typo mistake. I have fixed this. @ChauTranAnna
Seems control is an object, therefore you need to use a formGroup instead of a formcontrol.Shend
Would you please show me how? @AJT_82Anna
@AJT_82 , You are suggesting to push FormGroup into FormArray rather than FormControl. Right? If I do this then there would be no need to use control object as I can define the properties in FormGroup which is to be pushed into FormArray. Please tell, Am I following correct approach now?Anna
Yes, if you do not need control for anything else, push a formgroup with the properties and values you want.Shend
Alright, Thanks for help.Anna
@AJT_82, Please verify the way I'm pushing formgroup into formarray, is it right? I am doing: (<FormArray>this.reviewForm.get('controlArray')).push(this.fb.group({ controlType: control.controlType, label: control.label, }));Anna
Yes that looks correct to me :) Isn't it working?Shend
@AJT_82, Yes, its not working. Getting these errors: FormListComponent_Host.html:1 ERROR TypeError: this.validator is not a function at FormControl.webpackJsonp.../../../forms/@angular/forms.es5.js.AbstractControl._runValidator (forms.es5.js:2720) at new FormControl (forms.es5.js:3011) at FormBuilder.webpackJsonp.../../../forms/@angular/forms.es5.js.FormBuilder._createControl (forms.es5.js:5898) at FormListComponent.webpackJsonp.../../../../../src/app/form/form-list.component.ts.FormListComponent.addForm (form-list.component.ts:75)Anna
create a demo and I can take a look at it.Shend
@AJT_82 The application first loads data from Mongodb and display it, I don't think online project can have this functionality. It is a mean stack application, can I send you this project by email?Anna
Just use dummy data which would represent your model. Unfortunately I don't have time to run a project locally, also I am at work currently :DShend
Alright, I am working on it now, If I'm unable to find the solution, I'll ask you for help. Thanks to remain supportive.Anna
A
3

You can bind this way:

reviewForm.controls.controlArray.controls[i].controls.DATAYOULIKEBIND.value
Angel answered 27/1, 2018 at 22:39 Comment(0)
C
3

I had the same problem and solved it with a getter in the component class.

get controlArray(): FormArray {
    return <FormArray> this.reviewForm.get('controlArray');
}

Note the cast to FormArray, otherwise the getter returns AbstractControl and you can't access any of the array properties or functions.

Then in the template you can do something like this.

<div formArrayName="controlArray">
    <div *ngFor="let control of controlArray.controls; let i = index" >
Contrived answered 5/12, 2018 at 16:39 Comment(3)
Similar to that. See the example at angular.io/api/forms/FormArrayName#exampleDactylic
...Then using the i variable as the [formControlName] for your control elements.Dactylic
Remember that I answered this question in Dec 2018 when Angular 7 was the latest version. The docs will be up to date for the latest version.Contrived
E
0

You should do something like this. Add [formGroupName]=i to next div where you have added formArray. So that Angular knows the correct traversal. Hope this helps. I had the same issue sometime before and this fix helped me

<div formArrayName="controlArray"> <div [formGroupName]=i *ngFor="let control of reviewForm.get('controlArray').controls; let i = index">

Espinoza answered 8/5, 2018 at 14:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.