Search code examples
angulartypescriptangular-reactive-formsformarray

Angular FormArray setValue with data from Service


I have a Problem with FormArray and could need some help. I have a form with variable FormArray and it works and I can send the data to the backend. The problem is, that I cant set the values from the data I receive from the backend.

This is the Typescript Code:

this.form = this.fb.group({
  title: new FormControl("",[Validators.required]),
  actors: new FormArray([])
})

this.moviesService.getMovie(this.movieId).subscribe(movieData => {
  this.movie = movieData;
  this.form.patchValue({
    title: this.movie.title,
    actors: this.movie.actors,           
  })
})

then on button click in html I call this functions:

addActor(){
  const actorsForm = this.fb.group({
    actor: '',
    role: ''
  })
  this.actors.push(actorsForm);
}

removeActor(i: number){
  this.actors.removeAt(i);
}

And the HTML:

<form [formGroup]="form" (submit)="onSubmit()">
  <table  formArrayName="actors">
    <tr>
      <th colspan="2">Besetzung:</th>
      <th width="150px">
        <button type="button" mat-stroked-button color="primary" (click)="addActor()">Hinzufügen +</button>
      </th>
    </tr>
    <tr *ngFor="let actor of form.get('actors')['controls']; let i=index" [formGroupName]="i">
      <td>
        Darsteller:
        <input type="text" formControlName="actor" class="form-control">
      </td>
      <td>
        Rolle:
        <input type="text" formControlName="role" class="form-control">
      </td>
      <td>
        <button (click)="removeActor(i)" mat-stroked-button color="warn">Remove</button>
      </td>
    </tr>
  </table>
  <button mat-raised-button color="primary" type="submit">Film speichern</button>
</form>

So my question is: How do I get the Data from the movieService in the actors Array?

actors: this.movie.actors doesn't work, I know I have to iterate through the array but don't know how.

Edit: Ok, I saw I got the first object from the array but if I add more actors it will just show the first.


Solution

  • Assumption:

    Expected that the API response data received will be:

    {
      "title": "James Bond 007",
      "actors": [
        { "id": 5, "role": "test", "actor": "test" },
        { "id": 6, "role": "test", "actor": "test2" }
      ]
    }
    

    I don't think that can directly patchValue for FormArray. Instead, iterate movie.actors with map in order to push FormGroup to actors FormArray.

    this.movie.actors.map(
      (actor: any) => {
        const actorsForm = this.fb.group({
          actor: actor.actor,
          role: actor.role,
        });
    
        this.actors.push(actorsForm);
      }
    );
    
    this.form.patchValue({
      title: this.movie.title,
    });
    

    Note: Since you implement actors getter, you can simplify

    form.get('actors')['controls']
    

    to:

    actors.controls
    

    HTML

    <tr
      *ngFor="let actor of actors.controls; let i = index"
      [formGroupName]="i"
    >
    
    </tr>
    

    Sample Solution on StackBlitz