Forms are an inevitable part of any front-end development project — they’re the basis of how applications collect data. Angular attempts to simplify the form creation process by providing two approaches to tackling form development: template-driven forms and reactive forms.
What’s the difference? Template-driven forms are managed in the HTML template, whereas reactive forms are managed in the component.
When to use one over the other? The template-driven option is good for basic forms with a fixed number of inputs and validation of the entire form, instead of each individual input. Reactive-driven forms are best for complex forms with a dynamic number of inputs, validation of each input and projects that require unit testing.
As the title of this article indicates, we’ll be looking at reactive forms. Why reactive forms? I’ve experienced the power of reactive forms on client projects and how relatively simple it is to develop complex forms.
For you to get the most out of this article, I recommend you have some basic Angular 2+ knowledge.
During this step-by-step guide, the technologies we’ll use are TypeScript and Angular’s Command-Line Interface (CLI). (To use the CLI, you’ll need Node/NPM installed, which we’ll cover as we go along.) Although the example form we’re building doesn’t have submit functionality, it highlights the basics of Angular’s reactive forms, including:
- Validation for required fields, proper email formatting
- Showing/hiding validation messages
- Dynamically adding/removing CSS classes based on validations
- Disabling/enabling the Submit button
- Resetting the form
Project setup with Angular CLI
To simplify the setup process, we’ll leverage Angular CLI. To install the CLI, if you don’t have it already, follow along with Angular’s documentation.
Paraphrasing the documentation:
- Ensure you have Node 6.9+ and NPM 3+ installed. You can check by entering the following commands in your command prompt/terminal. If you find they need to be installed or updated, check out https://nodejs.org/en/.
- After installing/updating Node and NPM, we’ll need to install TypeScript and the Angular CLI:
npm intall -g typescript @angular/cli
Creating and serving the project
In the command prompt, navigate to a directory where you’d like your project to live and create the project by entering:
ng new reactive-forms-app
ng serve OR npm start
The application should be running now. Check it out on http://localhost:4200/, unless you’ve specified a different port. After you save the changes you make during development, the browser will refresh automatically.
Creating the component
Using Angular CLI to create the component
We’re ready to make the component; the CLI will create the template, component, CSS and test files for you. Inside the root of the project’s directory enter:
ng generate component reactive-form
Reference form modules and the new component
Because we’re using Angular forms, we must import the appropriate modules for our project in the app.module.ts file, located in the app directory. The modules we need are: FormsModule and ReactiveFormsModule from @angular/forms.
In the @NGModule decorator, we need to reference the modules we just imported in the file. We need to place them inside the imports array. We also need to reference the reactive-form component we just created. Open your favorite code editor and paste in this code:
Updating the template
After the CLI generates the component, we’ll plug in the HTML for the form in the reactive-form.comonent.html file:
Updating the component TypeScript file
We’ll talk about what’s going on in the other elements of the template, but for now, we’ll cover the crux of Angular reactive forms: the component. Below is the completed reactive-form.component.ts file.
To tie our form into Angular, we need to import the appropriate classes into the component from @angular/forms. Specifically:
FormGroup, FormBuilder, Validators, AbstractControl and FormControl
After the import, we need to inject FormBuilder in the constructor. FormBuilder does the heavy lifting for us in reactive forms. I’m using Angular’s recommended method for injecting FormBuilder into our component, and I’m naming it “fb” to reference it throughout the component.
We’re initializing the form inside Angular’s ngOnInit lifecycle hook. I made initializeForm() a method so that when the user clicks the Clear button, the form is reset to its initial state.
Let’s cover what else is going on in the component.
Stores a reference to the form so we can use it throughout the component; this is the same name we used as the FormGroup attribute on the form element.
Allows us to reference an input. This is best explained by an example: Without the AbstractControl, we’d have to reference our inputs in the validation messages as:
With the AbstractControl, we can concisely reference the input as:
Give us access to Angular’s built-in validators and allow us to create our own and reference them in the template. For example:
The parameter of this fb.group method accepts an object, where each FormControl is a key and the property of the key is an array. At the zero index, the string is the default value of the input. And at the first index, we’re referencing the validators. If you have multiple validations for an input, you must use the compose method on the validators class.
Toggling validation messages and CSS classes
We’ll only show validation error messages if there’s an error, and if the user “touched” the input. We covered this when we talked about AbstractControls, but we’ll dig a little deeper into validations.
Thanks to the FormBuilder, our inputs (FormControls) have access to a variety of methods and properties, specifically valid, touched and hasError():
- FormControlName.valid checks the validity of the input.
- FormControlName.touched has the user touched and navigated away from the input.
- FormControlName.hasError() checks for different errors. This method accepts built-in and custom validators; we created our custom email validator called “invalidEmail.”
We can also toggle CSS classes based on the valid and touched properties available. For example, we’re only adding the error class to the input if the field is invalid and the field was touched:
Disabling the Submit button and clearing the form
Just as our input fields have properties and methods, FormBuilder provides functionality to the form itself. Using these properties is how we disable the Submit button, until the fields are valid.
To clear or reset the form, we call the initializeForm method on the click event.
Final step: Updating the app.component.html file
Open the app.component.html file and reference the element/component inside the app.component.html. In the file, you should have:
Once you’ve saved the changes to the app.component.html file, you should have a working form.
Tips when developing reactive forms
When you’re on your own developing an Angular reactive form, remember the following tips to avoid snafus and make development a little easier:
- Ensure the values for the FormGroup and FormControl attributes in the HTML match the variable names in your TypeScript file.
- Import the FormsModule and ReactiveFormsModule in your project.
- Using the AbstractControl type will make it easier to reference your form inputs.
- Only display validation error messages if the user touched the input and there’s an error; otherwise, your user will see validation error messages when the form loads.
Hopefully, you’ve discovered the value of using reactive forms and will incorporate them in your next Angular project.
This article originally appeared on July 2, 2018.