As we progress through the depths of Angular 18, we're delving into how to build forms - those digital fields where you input your information online. Our starting point? Crafting a basic contact form to lay the groundwork for understanding the essentials.
To build our form, we're tapping into Angular's toolbox, leveraging the FormGroup
and FormBuilder
components. These act as our building blocks, enabling us to create forms that react dynamically to user input, clicks, and submissions.
In addition to these foundational elements, we're acquainting ourselves with another approach in Angular form creation - the template-based approach. This method relies on special directives like ngForm, ngSubmit, and ngModel to simplify the form-building process.
By the end of our journey, we'll learn about how to work with forms in Angular 18, equipped with the necessary knowledge to gather ans submit information from our application users!
For our hands-on practice, we'll be using StackBlitz, an online IDE that streamlines Angular development. Just sign in with your GitHub credentials, select a ready-made Angular template, and you're all set to START A NEW APP powered by the latest Angular 18 version.
Angular 18 offers two distinct methods for handling forms: the template-based strategy and the model-based strategy. Each has its own advantages, so feel free to choose the one that suits your needs best!
Creating an Angular 18 Template-Based Form
Let's kick off our journey by constructing a simple Angular 18 form using the template-based approach. Let's tweak some settings to get things rolling.
Importing the Angular Forms Module
We'll start by opening the src/app/app.component.ts
file and importing the FormsModule
. Then, we add it to the imports
array:
import { Component } from '@angular/core';import { FormsModule } from '@angular/forms';import { RouterOutlet } from '@angular/router';@Component({ selector: 'app-root', standalone: true, imports: [RouterOutlet, FormsModule], templateUrl: './app.component.html', styleUrl: './app.component.css'})export class AppComponent { title = 'angular18forms';}
This imports the forms module from @angular/forms
. The FormsModule is required when working with template-driven forms in Angular.
That's all we need to do to work with template-based forms in our standalone component.
Adding Angular Forms Directives
Next, open the src/app/app.component.html
file, remove evrything and add the following code:
<h2>Angular 18 Template-Based Contact Form Example</h2><form #myform="ngForm" (ngSubmit)="onSubmit(myform)"> <input type="text" name="fullName" placeholder="Your full name" ngModel /> <input type="email" name="email" placeholder="Your email" ngModel /> <textarea name="message" placeholder="Your message" ngModel></textarea> <input type="submit" value="Send" /></form>
Here, we're creating our form entirely within the Angular template. We first add a template reference variable to the form and assign the ngForm
key to it using the #myform="ngForm"
syntax. This allows us to access the form via the myform
reference.
Next, we bind the ngSubmit
event to the onSubmit()
method (which we'll add to our component next) and pass in the form object (via the local template variable).
Then, we register the child controls with the form. We simply add the ngModel
directive and a name
attribute to each element.
According to the docs, NgForm
creates a top-level FormGroup
instance and binds it to a form to track aggregate form value and validation status. This is done automatically when FormsModule
is imported.
Now, let's add some styling. Open the src/styles.css
and the add following CSS styles:
/* You can add global styles to this file, and also import other style files */body { width: 100%; height: 100vh; display: flex; align-items: center; justify-content: center;}
Next, open the src/app/app.component.css
file and add:
form { display: flex; flex-direction: column;}form * { margin: 10px; padding: 12px; border-radius: 10px; border: 1px dashed #410d0d;}
Submitting the Angular 18 Template Form
Next, let's add the onSubmit()
method to the component. Open the src/app/app.component.ts
file and add the following code:
import { Component } from '@angular/core';import { FormsModule, NgForm } from '@angular/forms';import { RouterOutlet } from '@angular/router';@Component({ selector: 'app-root', standalone: true, imports: [RouterOutlet, FormsModule], templateUrl: './app.component.html', styleUrl: './app.component.css'})export class AppComponent { title = 'angular18forms'; onSubmit(form: NgForm) { console.log('Your form data:', form.value); }}
We pass in the reference to the NgForm
object, representing our form, to the onSubmit()
method, which we then use to access various properties like value
, providing a plain JS object containing the form data. In this example, we simply print the form value in the console.
Here's a screenshot of our form UI:
Creating an Angular 18 Reactive Form
After crafting our Angular 18 contact form using the template-based approach, let's explore creating the same example using the reactive (model-based) approach.
First, go to the src/app/app.component.ts
file and import ReactiveFormsModule
as follows:
import { ReactiveFormsModule } from '@angular/forms';
Next, add them to the imports
array of the component:
import { Component } from '@angular/core';import { FormsModule, NgForm, ReactiveFormsModule } from '@angular/forms';import { RouterOutlet } from '@angular/router';@Component({ selector: 'app-root', standalone: true, imports: [RouterOutlet, FormsModule, ReactiveFormsModule], templateUrl: './app.component.html', styleUrl: './app.component.css'})export class AppComponent { /* [...] */}
Importing Angular's FormGroup
and FormBuilder
Classes
Next, in the same src/app/app.component.ts
file, import the FormGroup
and FormBuilder
classes as follows:
import { FormGroup, FormBuilder } from '@angular/forms';
Creating a Form Group and Injecting Angular's FormBuilder
Now, define the contactForm
object, which will hold our form object (an instance of FormGroup
), and inject FormBuilder
via the component constructor:
import { Component } from '@angular/core';import { FormBuilder, FormGroup, FormsModule, NgForm, ReactiveFormsModule } from '@angular/forms';import { RouterOutlet } from '@angular/router';@Component({ selector: 'app-root', standalone: true, imports: [RouterOutlet, FormsModule, ReactiveFormsModule], templateUrl: './app.component.html', styleUrl: './app.component.css'})export class AppComponent { title = 'angular18forms'; contactForm!: FormGroup; constructor(private formBuilder: FormBuilder){}}
Building the Form with Angular's FormBuilder
Next, define a createContactForm()
method where we'll build our form:
createContactForm() { this.contactForm = this.formBuilder.group({ fullName: [''], email: [''], message: [''] }); }
We call the group()
method of the injected instance of FormBuilder
to create a FormGroup
of three controls: fullName
, email
, and message
. Each control can take an optional array of options and validation rules.
Next, we call this method in the constructor:
constructor(private formBuilder: FormBuilder) { this.createContactForm();}
Submitting the Angular 18 Reactive Form
Finally, add the following method, which will be called when our form is submitted:
onSubmit() { console.log('Your form data:', this.contactForm.value); }
Now, we need to bind this form object to our HTML form. Open the src/app/app.component.html
file and add the following code:
<h2> Angular 18 Reactive Contact Form Example </h2><form [formGroup]="contactForm" (ngSubmit)="onSubmit()"> <input type="text" name="fullName" placeholder="Your full name" formControlName="fullName"> <input type="email" name="email" placeholder="Your email" formControlName="email"> <textarea name="message" placeholder="Your message" formControlName="message"></textarea> <input type="submit" value="Send"></form>
Here, we use property binding to bind the form using the formGroup
property. Next, we use formControlName
to sync the FormControl
objects in contactForm
with the HTML form controls by name. See the docs for more details. Finally, we bind the ngSubmit
event of the form to the onSubmit()
method.
Conclusion
In this tutorial, we've explored both the template-based and reactive (model-based) techniques for building a contact form in Angular 18. We've learned how to design a template-based form using directives like ngForm, ngSubmit, and ngModel, as well as a reactive form using the FormGroup and FormBuilder classes.
Date: