0

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.

2 Answers 2

1

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.

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

8 Comments

Thanks for the solution! It solves my array inside array problem. Anyway, my problem is with the <select> and <option> inputs. As you did in your demo, with text inputs works very well.
Hi, how is your <select> <option> look like? Does the formControl value match the value in <option>? Would be great if you can create a demo in StackBlitz.
Here is the demo: Demo @ StackBlitz. The <select> are there but I can't bind the data
Because your option is blank? Are you trying to render the details array as the options for <select> element?
Exactly. I want to bind the API response data to propagate the <select> and also bind the selected value. I was wrong with the FormArray concep. Thanks again!
|
0

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>

Comments

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.