Categories
Angular JavaScript

Introduction to Angular Forms

Spread the love

Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.

In this article, we’ll look at the basics of creating forms with Angular.

Different Kinds of Forms

Angular provides 2 different approaches to handling user input through forms.

They are either reactive or template-driven. They both capture events from the view, validate their user input, and create a form model and data model to update, and provide a way to track changes.

Reactive forms are more robust. They’re more scalable, reusable and testable.

Template-driven forms are useful for adding a simple form to an app. They’re easy to add, but they don’t scale as well as reactive forms.

Common Foundation

Both kinds of forms share the following building blocks:

  • FormControl — tracks the value and validation status of individual form controls
  • FormGroup — tracks the same value and status for a collection of form controls
  • FormArray — tracks the same value and status for an array of form control.s.
  • ControlValueAccessor — creates a bridge between Angular FormControl instances and native DOM elements.

Form Model Setup

We can set up the form model of a Reactive form by setting the formControl property of an input element.

For example, we can write the following code:

app.module.ts :

import { BrowserModule } from "@angular/platform-browser";  
import { NgModule } from "@angular/core";  
import { ReactiveFormsModule } from "@angular/forms";  
import { AppComponent } from "./app.component";

@NgModule({  
  declarations: [AppComponent],  
  imports: [BrowserModule, ReactiveFormsModule],  
  providers: [],  
  bootstrap: [AppComponent]  
})  
export class AppModule {}

app.component.ts :

import { Component } from "@angular/core";  
import { FormControl } from "@angular/forms";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  nameControl = new FormControl("");  
}

app.component.html :

<input type="text" [formControl]="nameControl" />

In the code above, we added the ReactiveFormsModule to our AppModule .

Then we created nameControl in AppComponent .

Finally, we set the formControl property to nameControl to connect the input to the FomControl .

Setup in Template-Driven Forms

We can use the ngModel directive to bind our input value to the a field in our component.

For example, we can write the following:

app.module.ts :

import { BrowserModule } from "@angular/platform-browser";  
import { NgModule } from "@angular/core";  
import { FormsModule } from "@angular/forms";  
import { AppComponent } from "./app.component";

@NgModule({  
  declarations: [AppComponent],  
  imports: [BrowserModule, FormsModule],  
  providers: [],  
  bootstrap: [AppComponent]  
})  
export class AppModule {}

app.component.ts :

import { Component } from "@angular/core";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  name: string;  
}

app.component.html :

<input type="text" [(ngModel)]="name" />

In the code above, we imported the FormsModule in app.module.ts .

Then we created the name field in AppComponent to bind the data to the field.

Then we bind our input’s value to name via ngModel .

Both Reactive and Template-Driven forms provide 2 way binding between the model and the input.

Data Flow in Reactive Forms

From view to model, the data flow follows the following steps:

  1. User types something into the input
  2. Form input emits an input event
  3. Control value accessor listens for events on the form input and sends the new value to the FormControl instance.
  4. The FormControl instance emits the new value through the valueChanges observable.
  5. Subscribes to valueChanges receive the new value

From model to view, the flow is as follows:

  1. The user calls the nameControl.setValue method to update the FormControl value
  2. The FormControl instance emits the new value through the valueChanges observable.
  3. Any subscribers to the valueChanges observable receive the new value
  4. The control value accessor on the form input element updates the element with the new value

Data Flow in Template-Driven Forms

The data from the view to the model in template-driven forms are as follows:

  1. User types something into the input element.
  2. The input element emits an input event with the value typed in
  3. The control value accessor attached to the input triggers the setValue method on the FormControl instance
  4. The FormControl instance emits the new value through valueChanges observable
  5. Any subscribers to the valueChanges observable receives the new value
  6. The control value accessor also calls NgModel.viewToModelUpdate method which emits an ngModelChange event
  7. ngModelChanges triggers model value update

From model to view, the flow is as follows:

  1. The value is updated in the component
  2. Change detection begins
  3. ngOnChanges is called on the NgModel directive instance because the input value has changed
  4. ngOnChanges queues an async task to set the value of the FormControl instance
  5. Change detection completes
  6. The task to set FormControl instance value is run on next tick
  7. FormControl instance emits the latest change through the valueChanges observable
  8. Any subscribers to the valueChanges observable receives the new value
  9. Control value accessor updates the form input element in the view

Conclusion

We can create Angular forms as Reactive or Template-Driven forms.

Reactive forms are more robust and Template-Driven forms are suitable for simple forms.

They both have the same parts. The control value accessor takes the input value and sets it to the model.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *