简体   繁体   中英

Nested Array in Angular Reactive Form

I have an assignment to create and edit volumes with angular. I am using reactive form but i cannot take volumes authors when i try to edit them. I am dynamically generating them when i am creating volume but i cannot see them on 'Edit'. I tried many ways and i was seeing all kind of errors on the browser console. Here is the code:

  public createMyVolumeForm: FormGroup;

  constructor(private fb: FormBuilder,
              private router: Router,
              private volumeService: VolumeService,
              private route: ActivatedRoute) {
    this.createMyVolumeForm = this.fb.group({
      id: ['', [Validators.required]],
      volumeInfo: this.fb.group({
        title: ['', [Validators.required]],
        authors: this.fb.array([
          this.fb.control('')
        ]),
        publisher: ['', [Validators.required]],
        publishedDate: ['', [Validators.required]],
        pageCount: ['', [Validators.required]],
        imageLinks: this.fb.group({
          thumbnail: ['', [Validators.required]]
        })
      })
    });
  }

  createMyVolume(): void {
    this.volumeService.createMyVolume(this.createMyVolumeForm.value)
      .subscribe(data => {
        this.router.navigateByUrl('my-volumes');
        console.log(this.createMyVolumeForm.value);
      });
  }

  ngOnInit(): void {
    this.route.paramMap.subscribe(params => {
      const volumeId = params.get('id');
      if (volumeId) {
        this.getCurrentVolume(volumeId);
      }
    });
  }

  private getCurrentVolume(id: string): void {
    this.volumeService.getVolume(id).pipe(take(1)).subscribe(
      (volume: IVolume) => this.editVolume(volume)
    );
  }

  private editVolume(volume: IVolume): void {
    this.createMyVolumeForm.patchValue({
      id: volume.id,
      volumeInfo: {
        title: volume.volumeInfo.title,
        publisher: volume.volumeInfo.publisher,
        authors: this.fb.group(this.authors),
        publishedDate: volume.volumeInfo.publishedDate,
        pageCount: volume.volumeInfo.pageCount,
        imageLinks: {
          thumbnail: volume.volumeInfo.imageLinks.thumbnail,
        }
      }
    });
  }

  get authors(): FormArray {
    return this.createMyVolumeForm.get('volumeInfo.authors') as FormArray;
  }

  addMoreAuthors() {
    this.authors.push(this.fb.control(''));
  }
}```

HTML: 
<section class="form-holder">
  <h2 class="form-heading">Create Volume</h2>
  <form [formGroup]='createMyVolumeForm'>
    <div class="input">
      <label class="required-input" for="id">Id</label> <input id="id" type="text" formControlName="id" name="id"/>
    </div>
    <div formGroupName="volumeInfo">
      <div class="input-holder">
        <label class="required-input" for="title">Title</label>
        <div class="input">
          <input id="title" type="text" formControlName="title" name="title"/>
        </div>
        <button type="submit" class="button" (click)="addMoreAuthors()">Add Authors</button>
        <div formArrayName="authors">
          <div *ngFor="let author of authors.controls; let i = index;">
            <label>Authors</label> <input type="text" [formControlName]="i">
          </div>
        </div>
        <label class="required-input" for="publisher">Publisher</label>
        <div class="input">
          <input id="publisher" type="text" formControlName="publisher" name="publisher">
        </div>
        <label class="required-input" for="publishedDate">Published Date</label>
        <div class="input">
          <input id="publishedDate" type="text" formControlName="publishedDate" name="publishedDate">
        </div>
        <label class="required-input" for="pageCount">Page Count</label>
        <div class="input">
          <input id="pageCount" type="number" formControlName="pageCount" name="pageCount">
        </div>
        <div formGroupName="imageLinks">
          <label class="required-input" for="thumbnail">Thumbnail</label>
          <div class="input">
            <input id="thumbnail" type="text" formControlName="thumbnail" name="thumbnail">
          </div>
        </div>
      </div>
      <div class="login-button-holder">
        <input class="login-button"
               type="submit"
               [disabled]="createMyVolumeForm.invalid"
               (click)="createMyVolume()" value="Create"/>
      </div>
    </div>
  </form>
</section>

FormArrays have a confusing API. Rather than being an a FormControl representing an array value , they represent an array of FormControls. So if you want to assign a set of authors to the form, each of which is editable, then you need to create a new control for each one, and add it to the FormArray.

Taking this as an example:

private editVolume(volume: IVolume): void {
    this.createMyVolumeForm.patchValue({
      id: volume.id,
      volumeInfo: {
        title: volume.volumeInfo.title,
        publisher: volume.volumeInfo.publisher,
        authors: this.fb.group(this.authors),
        publishedDate: volume.volumeInfo.publishedDate,
        pageCount: volume.volumeInfo.pageCount,
        imageLinks: {
          thumbnail: volume.volumeInfo.imageLinks.thumbnail,
        }
      }
    });
  }

One method is, where you are assigning to authors, instead do authors: new FormArray([]) .

Then after patching the value to the form, do something like:

(this.createMyVolumeForm.get('authors') as FormArray).clear();
this.authors.forEach(a => {
     const control = new FormControl(a);
     (this.createMyVolumeForm.get('authors') as FormArray).add(control);
});

Hopefully that gets you on the right track.

Thank you Jesse, your answer really put me on the right track with a little tweek:

 showExistingAuthors(volume: IVolume): void {
    (this.createMyVolumeForm.get('volumeInfo.authors') as FormArray).clear();
    volume.volumeInfo.authors.forEach(a => {
      const control = new FormControl(a);
      (this.createMyVolumeForm.get('volumeInfo.authors') as FormArray).push(control);
    });
  }```

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM