Home > Software engineering >  Angular 14: Propagate FormArray with API response to use in select option
Angular 14: Propagate FormArray with API response to use in select option

Time:01-30

I want to create several select option inputs with the response of an API.

I have defined this form with a FormArray input.

this.myForm = this.fb.group({
  name: [null, [Validators.required]],
  details: this.fb.array([], Validators.required),
});

Then, the getter for the detail input as FormArray.

get detailsArr() {
  return this.myForm.get('details') as FormArray;
}

I fetch data from a service and propagate the form values with the response. The response from the server for the details is something like this:

"details": [
  { "detailName": "detail 1", "detailValue": 2},
  { "detailName": "detail 2", "detailValue": 4},
  { "detailName": "detail 3", "detailValue": 5}
]
fetchData() {
  this.dataService.getData().subscribe((res) => {
    // Propagate details
    this.detailsArr.push(this.fb.control(res.details));

    // Propagate name
    this.myForm.patchValue({
      name: res.name,
    });
  });
}

The point is, I don't know how to set the value of the details array to the details response. With the push method I get an array inside an array, I mean:

"details": [
  [
    { "detailName": "detail 1", "detailValue": 2}
  ]
]

The HTML is the following:

<form [formGroup]="myForm">
  <div formArrayName="details">
    <select *ngFor="let detail of detailsArr.controls; let i = index" [formGroupName]="i">
      <option>{{ detail.detailName }}</option>
    </select>
  </div>
</form>

I tried with detailsArr.value in the for loop and seems to work, but don't know why.

I just have followed this Angular official documentation, but doesn't work. I don' know if this is the correct approach to solve this problem.

CodePudding user response:

For each element in the details array, you need to push it as FormGroup to detailsArr FormArray.

addDetailFormGroup(detail: any) {
  this.detailsArr.push(
    this.fb.group({
      detailName: detail.detailName,
      detailValue: detail.detailValue,
    })
  );
}
fetchData() {
  this.dataService.getData().subscribe((res) => {
    // Propagate details
    for (let detail of res.details) {
      this.addDetailFormGroup(detail);
    }

  ...
}

Demo @ StackBlitz

Updated

As clarified with Post Owner, he wants to bind the data received from the API response as the options in the <select> element, the FormArray shouldn't be used in his scenario. FormArray is used when the form requires to render the element which contains multiple FormControl or FormGroup.

CodePudding user response:

The solution is the one posted by @Youn Shun.

I have just added some variables and inputs to control the selected value, but with this approach all works perfectly.

Demo @StackBlitz

export class AppComponent {
  name = 'Angular '   VERSION.major;
  myForm: FormGroup;
  details: any[];
  detailSelected: any;

  constructor(private fb: FormBuilder, private dataService: DataService) {}

  ngOnInit() {
    this.myForm = this.fb.group({
      name: [null, [Validators.required]],
      detailSelected: ['', Validators.required],
    });

    this.fetchData();
  }

  fetchData() {
    this.dataService.getData().subscribe((res) => {
      this.details = res.details;

      this.myForm.patchValue({
        name: res.name,
        detailSelected: this.myForm.value.detailSelected,
      });
    });
  }
}

<form [formGroup]="myForm">
  Name: <input formControlName="name" />
  <label for="detailSelected">Detail:</label>
  <select id="detailSelected" formControlName="detailSelected">
    <ng-container *ngFor="let detail of details">
      <option [value]="detail.detailValue">{{ detail.detailName }}</option>
    </ng-container>
  </select>

  <button type="submit">Submit</button>
</form>
  • Related