Comprehensive Guide to Angular Forms: Fundamental Concepts and Examples

Manthan Ankolekar - Jun 12 - - Dev Community

Angular provides a robust framework for handling forms with both template-driven and reactive approaches. This guide will walk you through the key concepts and offer code examples for each.

1. Fundamental Concepts of Angular Forms

Angular forms enable the capture and validation of user input. They come in two flavors: Template-Driven and Reactive. Both approaches provide ways to bind user input to model data and validate that data.

2. Template-Driven Forms in Angular

Template-driven forms rely on Angular directives to create and manage forms within the HTML template.

HTML:

<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)">
  <div>
    <label for="name">Name</label>
    <input type="text" id="name" name="name" ngModel required>
  </div>
  <div>
    <label for="email">Email</label>
    <input type="email" id="email" name="email" ngModel required>
  </div>
  <button type="submit" [disabled]="myForm.invalid">Submit</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Component:

import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';

@Component({
  selector: 'app-template-driven-form',
  templateUrl: './template-driven-form.component.html'
})
export class TemplateDrivenFormComponent {
  onSubmit(form: NgForm) {
    console.log('Form Data:', form.value);
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Set Value in Template-Driven Forms

To programmatically set values in a template-driven form:

HTML:

<button type="button" (click)="setFormValue()">Set Form Value</button>
Enter fullscreen mode Exit fullscreen mode

Component:

import { ViewChild, AfterViewInit } from '@angular/core';

@Component({
  selector: 'app-template-driven-form',
  templateUrl: './template-driven-form.component.html'
})
export class TemplateDrivenFormComponent implements AfterViewInit {
  @ViewChild('myForm') form: NgForm;

  ngAfterViewInit() {
    // Ensure the form is available
  }

  setFormValue() {
    if (this.form) {
      this.form.setValue({
        name: 'John Doe',
        email: 'john.doe@example.com'
      });
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

4. Reactive Forms in Angular

Reactive forms are more flexible and scalable, allowing the use of reactive programming techniques.

HTML:

<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
  <div>
    <label for="name">Name</label>
    <input id="name" formControlName="name">
  </div>
  <div>
    <label for="email">Email</label>
    <input id="email" formControlName="email">
  </div>
  <button type="submit" [disabled]="myForm.invalid">Submit</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Component:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-reactive-form',
  templateUrl: './reactive-form.component.html'
})
export class ReactiveFormComponent implements OnInit {
  myForm: FormGroup;

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.myForm = this.fb.group({
      name: ['', Validators.required],
      email: ['', [Validators.required, Validators.email]]
    });
  }

  onSubmit() {
    console.log('Form Data:', this.myForm.value);
  }
}
Enter fullscreen mode Exit fullscreen mode

5. FormBuilder in Reactive Forms

FormBuilder simplifies the creation of form controls.

Component:

constructor(private fb: FormBuilder) {
  this.myForm = this.fb.group({
    name: ['', Validators.required],
    email: ['', [Validators.required, Validators.email]]
  });
}
Enter fullscreen mode Exit fullscreen mode

6. SetValue & PatchValue in Angular

setValue sets the value for all controls, while patchValue allows partial updates.

Component:

setFormValue() {
  this.myForm.setValue({
    name: 'John Doe',
    email: 'john.doe@example.com'
  });
}

patchFormValue() {
  this.myForm.patchValue({
    email: 'john.doe@example.com'
  });
}
Enter fullscreen mode Exit fullscreen mode

7. StatusChanges in Angular Forms

statusChanges emits an event whenever the form's validation status changes.

Component:

ngOnInit() {
  this.myForm.statusChanges.subscribe(status => {
    console.log('Form Status:', status);
  });
}
Enter fullscreen mode Exit fullscreen mode

8. ValueChanges in Angular Forms

valueChanges emits an event whenever the value of the form or any control changes.

Component:

ngOnInit() {
  this.myForm.valueChanges.subscribe(value => {
    console.log('Form Value:', value);
  });
}
Enter fullscreen mode Exit fullscreen mode

9. FormControl

FormControl is used to create individual form controls.

Component:

const nameControl = new FormControl('John Doe', Validators.required);
Enter fullscreen mode Exit fullscreen mode

10. FormGroup

FormGroup aggregates multiple FormControl instances into a single group.

Component:

this.myForm = new FormGroup({
  name: new FormControl('John Doe', Validators.required),
  email: new FormControl('john.doe@example.com', [Validators.required, Validators.email])
});
Enter fullscreen mode Exit fullscreen mode

11. FormArray Example

FormArray can manage an array of FormControl, FormGroup, or other FormArray instances.

HTML:

<div formArrayName="emails">
  <div *ngFor="let email of emails.controls; let i=index">
    <label for="email{{i}}">Email {{i + 1}}</label>
    <input [id]="'email' + i" [formControlName]="i">
  </div>
</div>
<button type="button" (click)="addEmail()">Add Email</button>
Enter fullscreen mode Exit fullscreen mode

Component:

get emails() {
  return this.myForm.get('emails') as FormArray;
}

addEmail() {
  this.emails.push(new FormControl('', [Validators.required, Validators.email]));
}

ngOnInit() {
  this.myForm = this.fb.group({
    name: ['', Validators.required],
    email: ['', [Validators.required, Validators.email]],
    emails: this.fb.array([this.fb.control('', [Validators.required, Validators.email])])
  });
}
Enter fullscreen mode Exit fullscreen mode

12. Build Dynamic or Nested Forms using FormArray

FormArray allows for dynamic forms, where users can add or remove controls as needed.

Component:

addEmail() {
  this.emails.push(this.fb.control('', [Validators.required, Validators.email]));
}
Enter fullscreen mode Exit fullscreen mode

13. SetValue & PatchValue in FormArray

setValue and patchValue can also be used with FormArray.

Component:

setEmails() {
  this.emails.setValue(['email1@example.com', 'email2@example.com']);
}

patchEmails() {
  this.emails.patchValue(['email1@example.com']);
}
Enter fullscreen mode Exit fullscreen mode

14. Select Options Dropdown

Dropdowns can be easily integrated with forms.

HTML:

<label for="selectedOption">Select Option</label>
<select id="selectedOption" formControlName="selectedOption">
  <option *ngFor="let option of options" [value]="option">{{option}}</option>
</select>
Enter fullscreen mode Exit fullscreen mode

Component:

options = ['Option 1', 'Option 2', 'Option 3'];

ngOnInit() {
  this.myForm = this.fb.group({
    selectedOption: ['', Validators.required]
  });
}
Enter fullscreen mode Exit fullscreen mode

15. Typed Forms in Angular

Typed forms improve type safety for form controls.

Component:

interface FormModel {
  name: string;
  email: string;
}

const form: FormGroup<FormModel> = new FormGroup({
  name: new FormControl<string>(''),
  email: new FormControl<string>('')
});
Enter fullscreen mode Exit fullscreen mode

16. FormRecord in Angular

FormRecord allows for dynamic control creation in form groups.

Component:

const record: FormRecord<FormControl<string>> = new FormRecord({
  dynamicKey: new FormControl<string>('Initial Value')
});

record.addControl('newKey', new FormControl<string>('New Value'));
Enter fullscreen mode Exit fullscreen mode

Conclusion

This guide covers the essential concepts of Angular forms, providing you with the knowledge to build both template-driven and reactive forms. By understanding these concepts and using the provided code examples, you can create robust, dynamic, and type-safe forms in your Angular applications.

Happy coding!

Exploring the Code

Visit the GitHub repository to explore the code in detail.


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .