Kars
Kars

Reputation: 917

Angular formControl how to handle array property

I have the following Angular form:

<form [formGroup]="futureForm" (ngSubmit)="onSaveFuture(futureForm.value)">
    // ...

    <div class="row" *ngFor="let value of atr.values" >
        <div class="col-md-6">
          <input type="text" class="form-control form-control-sm" value="{{value.prop1}}"
                 formControlName="values.prop1">
        </div>
        <div class="col-md-3">
          <input type="text" class="form-control form-control-sm" value="{{value.prop2}}"
                 formControlName="values.prop2">
        </div>
        <div class="col-md-3">
          <input type="text" class="form-control form-control-sm" value="{{value.prop3}}"
                 formControlName="values.prop3">
        </div>
    </div>

    // ...
</form>

Note that formGroup name is futureForm and on submit we are calling onSaveFuture.

My problem is that atr.values, which is being looped through with *ngFor, is an array. I want futureForm.value (the parameter that gets passed to the saveFuture function) to contain the array with value objects in it when the form gets submitted.

The following problem occurs. The console says this:

Cannot find control with name: 'values.prop1'

Also on submit, i am not getting the array that i want. atr.values is not even an array, but a single object.

How do i make it so that my different inputs will correspond to their respective atr.values entry so that the value is shown and also passed as an array to the onSaveFuture function?

My component looks like this:

export class SomeComponent implements OnInit {
  atr: IAtr;
  futureForm;

    // constructor..

    ngOnInit(): void {
        // ..
        this.futureForm = this.formBuilder.group({
          // ..
          values: this.atr.values,
        });
    }

    // onSaveFuture..
}

Is there something i am missing, or do i need to use something other than formControlName?? Thanks in advance.

Upvotes: 0

Views: 2641

Answers (1)

bryan60
bryan60

Reputation: 29335

if you're data is an array, you need a FormArray which is a little more complex than normal form groups.

ngOnInit(): void {
    // ..
    this.futureForm = this.formBuilder.group({
      // ..
      // initialize with array of groups
      values: this.formBuilder.array(this.atr.values.map(v => this.getValueGroup(v))),
    });

}

get valuesForm() {
  return this.futureForm.get('values') as FormArray
}

private getValueGroup(v?) {
  return this.formBuilder.group({
     // value group properties
     prop1: [v ? v.prop1 : ''] // something like this, initialize to prop value or default, add validators or whatever
  })
}

addValue(v?) {
  // use this to add new values
  const vg = this.getValueGroup(v);
  this.valuesForm.push(vg);
}

removeValue(index: number) {
  // remove values
  this.valuesForm.removeAt(index);
}

then in template, things will look different too:

<ng-container formGroupName="values"> <!-- need some wrapper to build the path to the array... still uses formGroupName even though array --> 
    <div class="row" *ngFor="let ctrl of valuesForm.controls; let i = index" [formGroupName]="i"> <!-- iterate the controls,  group names are the index -->
        <div class="col-md-6">
          <input type="text" class="form-control form-control-sm"
                 formControlName="prop1"> <!-- just the property name, don't explicitly assign value -->
        </div>
        <div class="col-md-3">
          <input type="text" class="form-control form-control-sm" 
                 formControlName="prop2">
        </div>
        <div class="col-md-3">
          <input type="text" class="form-control form-control-sm" 
                 formControlName="prop3">
        </div>
    </div>
<ng-container>

Upvotes: 1

Related Questions