Angular Reactive Forms

Alex Onozor
alexonozor
Published in
7 min readSep 2, 2017

Data driven applications uses form as one of their biggest data input source. Two-ways-data-binding frameworks/libraries like Angular is doing pretty well because of it ng-model, which made creating dynamic forms easy.

Angular 2.X+ offers two form-building technologies: reactive forms and template-driven forms. The two technologies belong to the @angular/forms library and share a common set of form control classes but they diverge markedly in philosophy, programming style, and technique. They even have their own modules: the ReactiveFormsModule and the FormsModule.

In this article, we want to focus on Reactive From.

For demonstration, we are going to be building a simple user registration application but let’s use this time to talk about Reactive form.

Reactive Form

Angular reactive forms facilitate a reactive style of programming to get data in and out of the form from where it is been defined in the component to the template visa versa through the use of Form Model and Form Directives. Reactive forms offer the ease of using reactive patterns, testing, and validation.

Form Model

The form model is a UI-independent representation of a form. It consists of three building blocks: FormControl, FormGroup, and FormArray.

Form Directives

These are the directives connecting the form model to the DOM (e.g., NgModel). FormsModule and ReactiveFormsModule provide different sets of these directives. Let’s set them up!

Setup

A good place to start is the UI-independent(Form Model) so Let’s assume we are in our users Component class taking the FormControl.

Form Control

FormControl is a directive that allows you to create and manage a FormControl instance directly.

The above code shows a formControl called userName. this will be available in our template. A FormControl constructor accepts three, optional arguments: the initial data value, an array of validators, and an array of async validators. Notice our simple control doesn’t have a validator, lets bind it to our template.

Form Group

The above setup isn’t bad for a single FormControl, but what if we have multiple controls we want to bind in our template. it means we need to group them together with FormGroup which also allow nested grouping.

Now that you’ve made changes in the class, they need to be reflected in the template. Update user.component.html by replacing it with the following.

formGroup is a reactive form directive that takes an existing FormGroup instance and associates it with an HTML element. In this case, it associates the FormGroup you saved as userForm with the form element.

With a parent FormGroup, the userName input needs the syntaxformControlName="userName" in order to be associated with the correct FormControl in the class. This syntax tells Angular to look for the parent FormGroup, in this case userForm and then, inside that group to look for a FormControl called userName.

Let’s test to see if the value really works add the following line of code to see.

The userForm.value returns the form model. Piping it through the JsonPipe renders the model as JSON in the browser:

The initial userName property value is the empty string. Type into the name input box and watch the keystokes appear in the JSON.

Great! You have the basics of a form.

Nested FormGroups

Right now the user’s form only have userName and we need to add more fields to it like first name, last name, and address. Address will contain some fields like: street, city, Zip code. This means that our address needs to be nested, here is how our form group will look like.

We will bind the nested filed to the form in the template below. notice the new attribute called formGroupName have the address as a value, this directive instruct the form about where the nested group starts from in our case is address.

After these changes, the JSON output in the browser shows the revised form model with the nested address FormGroup:

The status of a group is calculated as follows:

  • If one of its children is invalid, the group is invalid.
  • If all of its children are valid, but the group itself has errors, the group is invalid.
  • If all of its children are valid, and the group has no errors, the group is valid.

At the moment, you’re dumping the entire form model onto the page. Sometimes you’re interested only in the state of one particular FormControl which we can achieve with the .get() method.

formControl has other handy method to check validity too.

Reactive form validation

Right now our form looks good and well nested, but what if we want to add validation to it? Well, the reactive form has a Hugh support for validations(Buit-in), it also gave us the ability to write a custom validation.

To start using reactive form validation, we need to import the Validation and import it into the user’s component.

`import { FormGroup, Validators } from ‘@angular/forms’;`

Built-in validators

Angular has three major built-in validators which are checks for presence (Validators.required) and length (Validators.maxLength, Validators.minLength). You can also support multiple validations using array, Let’s make use of them in our user Form.

We’ll validates the presence of userName and the minimum length should be 4 characters. here is the code.

What if we want to validate the style character of our username not to have some certain character? we need to write our own custom validation for it, Angular gives us the ability to do this.

Custom validations.

Since the built-in validators won’t always match the exact use case of your application, sometimes you’ll want to create a custom validator. Here is what a simple custom validation function looks like.

The forbiddenNameValidator factory returns the configured validator function. That function takes an Angular control object and returns either null if the control value is valid or a validation error object. The validation error object typically has a property whose name is the validation key, 'forbiddenName', and whose value is an arbitrary dictionary of values that you could insert into an error message, { userName }.

Adding to reactive forms

In reactive forms, custom validators are fairly simple to add. All you have to do is pass the function directly to the FormControl.

There are two types of validator functions: sync validators and async validators.

  • Sync validators: functions that take a control instance and immediately return either a set of validation errors or null. You can pass these in as the second argument when you instantiate a FormControl.
  • Async validators: functions that take a control instance and return a Promise or Observable that later emits a set of validation errors or null. You can pass these in as the third argument when you instantiate a FormControl.

Populate the form model with setValue and patchValue

Previously you created a control and initialized its value at the same time. You can also initialize or reset the values later with the setValue and patchValue methods.

setValue

With setValue, you assign every form control value at once by passing in a data object whose properties exactly match the form model behind the FormGroup.

The setValue method checks the data object thoroughly before assigning any form control values.

It will not accept a data object that doesn’t match the FormGroup structure or is missing values for any control in the group. This way, it can return helpful error messages if you have a typo or if you’ve nested controls incorrectly. patchValue will fail silently.

On the other hand,setValue will catch the error and report it clearly.

Notice that you can almost use the entire user as the argument to setValue because its shape is similar to the component's FormGroup structure.

patchValue

With patchValue, you can assign values to specific controls in a FormGroup by supplying an object of key/value pairs for just the controls of interest.

This example sets only the form’s userName control.

With patchValue you have more flexibility to cope with wildly divergent data and form models. But unlike setValue, patchValue cannot check for missing control values and does not throw helpful errors.

Reset the form flags

You can at any time rest the form to it initial states by using the .reset() method. you can also rest it to a stage by passing a params to it.

Wrapping Up

This article covered:

  • How to create a reactive form component and its corresponding template.
  • Grouping FormControls.
  • inbuilt-validation & Custom validation
  • Inspecting FormControl properties.
  • Setting data with patchValue and setValue.
  • Resting FormControls

It has been a long day for us reacting with Angular Reactive Forms :) . I will also recommend you to checkout out the this sample application built by the the Angular team, also do me a favor of reading the documentation about reactive forms.

See you next week….

--

--

Alex Onozor
alexonozor

Software Consultant, JavaScriptor, Web evangelist. Open source contributor. Software Architect.