5 tips on using Angular FormControl

Alain Chautard
Angular Training
Published in
4 min readApr 22, 2022

--

We often learn Angular presented with two options for working with forms: Template driven or reactive (or both!)

In several cases, small forms (for instance, a login screen, a single text input, or a single dropdown) don’t need that kind of verbosity.

In this post, we will look at five straightforward yet valuable features of the FormControl object used on its own without bringing any additional config to the table.

1. Using FormControl without FormBuilder on a single element

When we have one or two form elements, creating a FormControl object and binding it to the HTML element is pretty straightforward and gets the job done.

In the component class, all we need is:

myControl = new FormControl('default value');

And in our HTML template:

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

And that’s it! No need for a ngModel directive or a FormBuilder service. We can now access the value of that control with myControl.value, as illustrated in the complete code example below:

2. Getting the state of a control: pristine — dirty — valid -invalid-touched-untouched

Angular has six valuable properties on the FormControl object:

  • Pristine: true when the user has not changed the element value
  • Dirty: opposite of pristine — true when the user has changed the element value
  • Valid: true when the element value is valid against all validation rules applied to the element
  • Invalid: opposite of valid — true when the element value is not valid
  • Touched: true when the user has put focus on the element (say clicked on it) and then removed the focus from the element (clicked away from it)
  • Untouched: opposite of touched — means the user hasn’t put focus on the element or hasn’t removed that focus yet.

These six properties are accessible on the FormControl object and can be used to display feedback to the user, such as error messages or hints:

<input type="text" required [formControl]="myControl" />
<p>Valid: {{ myControl.valid }}</p>
<p>Touched: {{ myControl.touched }}</p>
<p>Dirty: {{ myControl.dirty }}</p>

Here is a complete example in action:

These six properties are also automatically set by Angular as CSS classes on the form element. As a result, adding some CSS class implementation for these properties is the easiest way to provide visual feedback to the user:

.ng-invalid {
background-color: pink;
}
.ng-dirty {
background-color: lightgray;
}

You can try those in the above example. First, clear the text input (for which a value is required) to see the ng-invalid class applied (pink background color) and type anything in the input to make it dirty (light gray background color applied).

3. Decide when the FormControl value gets updated with updateOn

By default, FormControl will update its value whenever the user changes the HTML form element value.

In some cases, we might want to wait for that update to trigger validation and value updates. That’s what the updateOn property is all about. We can delay the FormControl update process with one of these three options:

  • blur — The FormControl value updates when the HTML element blur event is sent (element loses focus)
  • submit — The FormControl value updates when the HTML element form is submitted.
  • change — The default behavior. User updates are reflected in real-time as the FormControl value.

The updateOn property is passed as a control option:

myControl = new FormControl('default value', { updateOn: 'blur' });

You can test this example with the complete example in Stackblitz below:

4. Resetting to the initial value instead of clearing the form with initialValueIsDefault

The default behavior of an HTML form on reset is to clear all values within that form.

In some cases, if we’re displaying a form in edit mode (say a user is using it to edit their profile information), it might be convenient to reset to the values before any edits were made, rather than clearing the entire form.

That’s where the nonNullable (which used to be known as initialValueIsDefault) control option makes perfect sense:

myControl = new FormControl('val', { nonNullable: true });

After we make edits to the form control, resetting the form will revert to the initial value rather than clearing the input.

You can try the two different behaviors in the example below:

5. Subscribing to form updates using the valueChanges and statusChanges observables

When we need to react to form updates using RxJs operators (to trigger an HTTP request or filter out a list coming from another observable, for instance), getting observables from our FormControl can be handy.

Two observables are public properties of FormControl:

  • valueChanges — Emits all value updates as soon as they happen
  • statusChanges — Emits all status updates (VALID or INVALID) as the user changes the form control value

We can subscribe to them in our component class or using the async pipe in our HTML template:

<p>Value changes: {{ myControl.valueChanges | async }}</p>
<p>Status changes: {{ myControl.statusChanges | async }}</p>

My name is Alain Chautard. I am a Google Developer Expert in Angular, as well as a consultant and trainer at Angular Training where I help web development teams learn and become comfortable with Angular.

If you need any help with web development, feel free to get in touch!

If you enjoyed this Angular tutorial, please clap for it or share it. Your help is always appreciated. You can also subscribe to Medium here.

--

--