I'm currently working on creating an array of books with multiple authors that can be added or removed dynamically.
As I delve into learning Angular, I've encountered the necessity of having a nested array within another array in my project.
The main objective is to generate an array of books where each book will contain a corresponding array of authors. However, I keep encountering the following error message:
Error: Cannot find control with path: 'books -> 0 -> authors -> 0
Below is the TypeScript code snippet I have implemented :
import { Component, Inject, OnInit } from '@angular/core';
import {FormArray, FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import {STEPPER_GLOBAL_OPTIONS} from '@angular/cdk/stepper';
/**
* @title Stepper that displays errors in the steps
*/
@Component({
selector: 'app-home',
templateUrl: 'home.component.html',
styleUrls: ['home.component.scss'],
providers: [
{
provide: STEPPER_GLOBAL_OPTIONS,
useValue: {showError: true},
},
],
})
export class HomeComponent implements OnInit {
bookForm: FormGroup;
constructor(private fb: FormBuilder) {
this.bookForm = this.fb.group({
books: this.fb.array([]) // Create an empty FormArray for books
});
}
ngOnInit(): void {
this.createBook()
}
get books() {
return this.bookForm.get('books') as FormArray;
}
addBook() {
this.books.push(this.createBook());
}
removeBook(index: number) {
this.books.removeAt(index);
}
createBook() {
return this.fb.group({
title: ['', Validators.required],
authors: this.fb.array([this.createAuthor()])
});
}
createAuthor() {
return this.fb.control('', Validators.required);
}
getAuthors(bookIndex: number) {
return this.books.at(bookIndex).get('authors') as FormArray;
}
addAuthor(bookIndex: number) {
const book = this.books.at(bookIndex) as FormGroup;
const authors = book.get('authors') as FormArray;
authors.push(this.createAuthor());
}
removeAuthor(bookIndex: number, authorIndex: number) {
const book = this.books.at(bookIndex) as FormGroup;
const authors = book.get('authors') as FormArray;
authors.removeAt(authorIndex);
}
onSubmit() {
if (this.bookForm.valid) {
console.log(this.bookForm.value);
}
}
}
Please find below the HTML code segment used:
<form [formGroup]="bookForm" (ngSubmit)="onSubmit()">
<div formArrayName="books">
<div *ngFor="let book of books.controls; let bookIndex = index">
<div [formGroupName]="bookIndex">
<div>
<label>
Book Title:
<input formControlName="title">
</label>
<button type="button" (click)="removeBook(bookIndex)">Remove Book</button>
</div>
<div formArrayName="authors">
<div *ngFor="let author of getAuthors(bookIndex).controls; let authorIndex = index">
<div [formGroupName]="authorIndex">
<label>
Author:
<input formControlName="authorName">
</label>
<button type="button" (click)="removeAuthor(bookIndex, authorIndex)">Remove Author</button>
</div>
</div>
<button type="button" (click)="addAuthor(bookIndex)">Add Author</button>
</div>
</div>
</div>
<button type="button" (click)="addBook()">Add Book</button>
</div>
<button type="submit">Submit</button>
</form>