Angular Form Array

juliegladden

Julie Gladden

Posted on November 29, 2024

Angular Form Array

Understanding Angular's FormArray

Angular's FormArray is a powerful tool in reactive forms (ReactiveFormsModule) that allows us to manage a dynamic set of form controls. Think of it as a flexible container for managing an array of form controls, particularly useful for forms where the number of inputs is variable, like a list of tasks, addresses, or phone numbers.

All code can be found here: AngularFormArrayTutorial - Github
Angular 19 Documentation: Reactive Forms Docs

What is FormArray?

A FormArray is similar to an array, but instead of storing regular values, it holds FormControl, FormGroup, or even other FormArray. Here's a breakdown:

  • FormControl: Manages a single value.
  • FormGroup: Manages a group of controls.
  • FormArray: Manages dynamic controls.

How to Use FormArray

Let’s explore a task management app example where FormArray handles dynamic tasks and their subtasks.

1. Initializing a FormArray

We start by creating a FormGroup containing a FormArray for managing tasks. Each task is represented as a FormGroup that includes a taskName FormControl and a subtasks FormArray.

constructor(private fb: FormBuilder) {
  this.tasksForm = this.fb.group({
    tasks: this.fb.array([]), // FormArray to manage tasks
  });
}
Enter fullscreen mode Exit fullscreen mode

2. Accessing the FormArray

To make the FormArray easily accessible, we define a getter:


// Getter for the tasks FormArray
get tasks(): FormArray {
  return this.tasksForm.get('tasks') as FormArray;
}

 // Helper to get subtasks FormArray for a specific task
  subtasks(index: number): FormArray {
    return (this.tasks.at(index) as FormGroup).get('subtasks') as FormArray;
}
Enter fullscreen mode Exit fullscreen mode

3. Adding New Controls Dynamically

To add a new task, we push a new FormGroup to the tasks FormArray. Each FormGroup includes:

  • A taskName FormControl.
  • A subtasks FormArray for nested subtasks.
addTask(taskName: string = '') {
  const taskGroup = this.fb.group({
    taskName: taskName || '', // Default to an empty string
    subtasks: this.fb.array([]), // Initialize an empty FormArray for subtasks
  });
  this.tasks.push(taskGroup); // Add the task to the tasks array
}
Enter fullscreen mode Exit fullscreen mode

Section 4: Adding Subtasks

To add a subtask to a specific task, we retrieve the subtasks FormArray for that task and push a new FormControl:

/*Uses the subtasks helper to get the subtask array, and then adds the new subtask at the end of the array. You could provide a starting value with another input, but for simplicities sake, we are pushing an empty string.*/
addSubtask(taskIndex: number, subtaskName: string = '') {
  this.subtasks(taskIndex).push(this.fb.control(subtaskName || ''));
}

Enter fullscreen mode Exit fullscreen mode

5. Removing Controls Dynamically

Removing tasks or subtasks with the the removeAt() method:

  • To remove a task:
removeTask(index: number) {
  this.tasks.removeAt(index);
}

//Uses the subtasks helper to get the subtask array, and then removes the subtask at the subtaskIndex
removeSubtask(taskIndex: number, subtaskIndex: number) {
  this.subtasks(taskIndex).removeAt(subtaskIndex);
}
Enter fullscreen mode Exit fullscreen mode

6. Template for Dynamic Tasks and Subtasks

Now let’s take a look at the HTML template that binds to the FormArray we’ve created in the component.

<form [formGroup]="tasksForm" class="tasks-form">
  <div formArrayName="tasks" class="tasks-list">
    @for (task of tasks.controls; track task; let i = $index) {
    <div [formGroupName]="i" class="task-item">
      <!-- Task Name -->
      <div class="main-task">
        <mat-form-field appearance="outline" class="task-field">
          <input matInput placeholder="Task Name" formControlName="taskName" />
        </mat-form-field>
        <button
          mat-mini-fab
          color="warn"
          (click)="removeTask(i)"
          class="delete-task-btn"
        >
          <mat-icon>check</mat-icon>
        </button>
      </div>

      <!-- Subtasks -->
      <div formArrayName="subtasks" class="subtasks-list">
        @for ( subtask of subtasks(i).controls; track subtask; let j = $index )
        {
        <div class="subtask-item">
          <mat-icon class="arrow">arrow_right</mat-icon>

          <mat-form-field appearance="outline" class="subtask-field">
            <input matInput placeholder="Subtask Name" [formControlName]="j" />
          </mat-form-field>
          <button
            mat-mini-fab
            color="warn"
            (click)="removeSubtask(i, j)"
            class="delete-subtask-btn"
          >
            <mat-icon>check</mat-icon>
          </button>
        </div>
        }
        <!-- Add Subtask Button -->
        <button
          mat-raised-button
          color="primary"
          (click)="addSubtask(i)"
          class="add-subtask-btn"
        >
          Add Subtask
        </button>
      </div>
    </div>
    }
  </div>

  <!-- Actions -->
  <div class="form-actions">
    <button mat-raised-button color="primary" (click)="loadSampleTasks()">
      Load Sample Tasks
    </button>
    <button mat-raised-button color="accent" (click)="clearAllTasks()">
      Clear Tasks
    </button>
    <button mat-raised-button color="primary" (click)="addTask()">
      Add Task
    </button>
  </div>
</form>

<!-- Displays the forms current data in real time json format. Really helpful for debugging.-->
<pre>{{ tasksForm.value | json }}</pre>

Enter fullscreen mode Exit fullscreen mode

Conclusion

The FormArray is an essential part of Angular's reactive forms when working with dynamic form controls. Whether you're building complex forms with nested controls or simple dynamic lists, FormArray provides a robust solution to handle the dynamic nature of your form controls in Angular.

Do you have an article you'd like to see? Let me know in the comments!

💖 💪 🙅 🚩
juliegladden
Julie Gladden

Posted on November 29, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Angular Form Array
angular Angular Form Array

November 29, 2024