Model-Driven/Reactive forms

The Model-Driven approach was specifically added in Angular 2+ to address the known limitations of the Template-Driven forms; the forms implemented with this alternative method are known as Model-Driven forms or Reactive forms.

The main difference here is that (almost) nothing happens in the template, which acts as a mere reference of a TypeScript object--the form model--that gets instantiated and configured programmatically within the component class.

To better understand the overall concept, let's try to rewrite the previous form in a Model-Driven/Reactive way (the relevant parts are highlighted):

<form [formGroup]="form" (ngSubmit)="onSubmit()">

<input formControlName="title" required />

<span *ngIf="(form.get('title').touched || form.get('title').dirty)
&& form.get('title').errors?.required">
Title is a required field: please enter a valid title.
</span>

<button type="submit" name="btnSubmit"
[disabled]="form.invalid">
Submit
</button>

</form>

Here's the underlying form model that we will define in the component class file (the relevant parts are highlighted):

import { FormGroup, FormControl, ReactiveFormsModule, Validators } from '@angular/forms';

class ModelFormComponent implements OnInit {
form: FormGroup;

ngOnInit() {
this.form = new FormGroup({
title: new FormControl()
});
}
}

Let's try to understand what's happening here:

  • The form property is an instance of FormGroup and represents the form itself
  • FormGroup, as the name suggests, is a container of form controls sharing the same purpose; as we can see, the form itself acts as a FormGroup, which means that we can nest FormGroup objects inside other FormGroups (we didn't do that in our sample, though)
  • Each data input element in the form template--in the preceding code, name--is represented by an instance of FormControl
  • Each FormControl instance encapsulates the related control's current state, such as valid, invalid, touched, and dirty, including its actual value
  • Each FormGroup instance encapsulates the state of each child control, meaning that it will be valid only if/when all its children are also valid

Also note that we have no way to access the FormControls directly, like we were doing in Template-Driven forms; we have to retrieve them using the .get() method of the main FormGroup, which is the form itself.

At first glance, the Model-Driven template doesn't seem much different from the Template-Driven one; we still have a form element, an input element hooked to a span validator, and a submit button; on top of that, checking the state of the input elements takes a bigger amount of source code, as they have no aliases we can use. Where's the real deal?

To help us visualize the difference, let's look at the following diagrams; here's a scheme depicting how Template-Driven Forms work:

By looking at the arrows we can easily see that, in Template-Driven Forms, everything happens in the template; the HTML form elements are directly bound to the component Data Model represented by a property filled with an asynchronous HTML request to the web server, such as the quiz: Quiz in our QuizEditComponent file. That Data Model will get updated as soon as the user changes something, unless some validator prevents them from doing that. If we think about it, we can easily understand how there isn't a single part of the whole workflow that happens to be under our control; Angular handles everything by itself, using the information found in the data bindings defined within our template. This is what Template-Driven actually means.

Let's now take a look at the Model-Driven Forms (or Reactive Forms) approach:

As we can see, the arrows depicting the Model-Driven Forms workflow tell a whole different story. They show how the data flows between the component Data Model--which we get from the web server--and a UI-oriented form model that retains the states and the values of the HTML form (and its children input elements) presented to the user. This means that we'll be able to get in the middle between the data and the form control objects and perform a number of tasks firsthand: push and pull data, detect and react to user changes, implement our own validation logic, perform unit tests, and so on.

Instead of being superseded by a template that's not under our control, we can track and influence the workflow programmatically, since the form model that calls the shots is also a TypeScript class; that's what Model-Driven is about. This also explains why they are also called Reactive Forms--an explicit reference to the Reactive programming style that favors explicit data handling and change management throughout the workflow.

For additional information on Model-Driven/Reactive Forms, we highly recommend you to read the official Angular documentation at https://angular.io/guide/reactive-forms.

Enough with the theory; it's time to empower our components with some Reactive forms.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.132.99