0

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>

2 Answers 2

1

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.

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

Comments

0

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);
    });
  }```

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.