Angular 16 Template Driven Form Validation with Bootstrap

Last Updated on by in Angular
In this Angular 16 Form tutorial, we are going to learn how to implement simple validation rules with the template-driven approach using Bootstrap forms.To validate the form, we will also look at how to use Bootstrap UI library to facilitate our form validation task.

In this Angular form example, we will create a basic form with some Input fields, such as name, email, password and hobbies.

In the previous tutorial, we implemented Angular form validation with Reactive Forms using Angular Material. However, we are going to take the diverse approach in this article.

By the end of this tutorial, you will understand following things:

  • How to quickly validate a form with template-driven approach in Angular.
  • How to create a form with Bootstrap form template.
  • How to bind ngModel directive with input controls to set the properties on the component.
  • How to submit the form with template driven approach.

Setting Up Angular Project

Run the below command to generate a brand new Angular project using Angular CLI.

ng new angular-template-driven-form

Head over to the Angular form project.

cd angular-template-driven-form

Install Bootstrap in Angular

Install Bootstrap UI framework via NPM using following command.

npm install bootstrap

Add the Bootstrap CSS path in styles array inside the angular.json file.

"styles": [
    "src/styles.css",
    "node_modules/bootstrap/dist/css/bootstrap.min.css"
]

No Property Access From Index Signature

To resolve error:

Property ‘xxxName’ comes from an index signature, so it must be accessed with [‘xxxName’]

This setting makes sure profound consistency between accessing a field via the “dot” (obj.key) syntax, and “indexed” (obj["key"]) and the way which the property is declared in the type.

Without this flag, TypeScript will allow you to use the dot syntax to access fields which are not defined:

Make sure to set noPropertyAccessFromIndexSignature property to false under compilerOptions in tsconfig.json file:

"compilerOptions": {
// ...
// ...
   "noPropertyAccessFromIndexSignature": false,
// ...
// ...
}

Importing FormsModule

To get started with Form control and NgModel Angular Forms service, we require to import FormsModule in app.module.ts file.

// app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})

export class AppModule { }

Create Form with Bootstrap From Template

Create a simple form in Angular using Bootstrap form component, open the app.component.html file and replace existing code with the following code.

<div class="container mt-5">
  <form novalidate>
    <div class="form-group mb-3">
      <label>Name</label>
      <input type="text" class="form-control" />
    </div>

    <div class="form-group mb-3">
      <label>Email</label>
      <input type="email" class="form-control" />
    </div>

    <div class="form-group mb-3">
      <label>Password</label>
      <input type="password" class="form-control" />
    </div>

    <div class="form-group mb-3">
      <label>Hobbies</label>
      <select class="form-control">
        <option value="">Select an option</option>
        <option *ngFor="let hoby of Hobbies" [value]="hoby">{{hoby}}</option>
      </select>
    </div>

    <div class="form-group mb-3">
      <button class="btn btn-danger">Submit</button>
    </div>
  </form>
</div>

Implement Template-driven Form in Angular

Now we will add the template-driven form using ngModel directive in Angular component.

Add the following code in the app.component.html file to initialize the Angular template-driven form.

<div class="container mt-5">
  <form
    #userForm="ngForm"
    (ngSubmit)="userForm.form.valid && onSubmit(userForm)"
  >
    <div class="form-group mb-3">
      <label>Name</label>
      <input
        type="text"
        name="name"
        class="form-control"
        [(ngModel)]="model.name"
        #name="ngModel"
        [ngClass]="{ 'is-invalid': userForm.submitted && name.invalid }"
        required
      />
    </div>

    <div class="form-group mb-3">
      <label>Email</label>
      <input
        type="email"
        class="form-control"
        name="email"
        [(ngModel)]="model.email"
        #email="ngModel"
        [ngClass]="{ 'is-invalid': userForm.submitted && email.invalid }"
        email
        required
      />
      <div *ngIf="userForm.submitted && email.invalid" class="invalid-feedback">
        <div *ngIf="email.errors.required">Email is required</div>
        <div *ngIf="email.errors.email">Must be a valid email address</div>
      </div>
    </div>

    <div class="form-group mb-3">
      <label>Password</label>
      <input
        type="password"
        class="form-control"
        name="password"
        [(ngModel)]="model.password"
        #password="ngModel"
        [ngClass]="{ 'is-invalid': userForm.submitted && password.invalid }"
        minlength="8"
        required
      />
      <div
        *ngIf="userForm.submitted && password.invalid"
        class="invalid-feedback"
      >
        <div *ngIf="password.errors.required">Password is required</div>
        <div *ngIf="password.errors.minlength">
          Password should be at least 8 characters long
        </div>
      </div>
    </div>

    <div class="form-group mb-3">
      <label>Hobbies</label>
      <select class="form-control" name="hobbies" [(ngModel)]="hobbies">
        <option value="">Select an option</option>
        <option *ngFor="let hoby of Hobbies" [value]="hoby">
          {{ hoby }}
        </option>
      </select>
    </div>

    <div class="form-group">
      <button class="btn btn-danger btn-block">Submit</button>
    </div>
  </form>
</div>

To initiate the template-driven form, add a reference to the NgForm. Declare a template variable with the form by adding the #userForm="ngForm".

To submit the form add onSubmit(userForm) event on the form tag.

When a user clicks on the submit button, then the input value will be passed through the onSubmit() method.

We also need to add a `name` property to the Angular form To register the form control in the form, and it is required to be added.

The ngModel directive formulates a FormControl instance in the Angular form and attaches it with the form control item.

From the hobbies option, a user can select one hobby, add a select field to the form and define the options as Hobbies using *ngFor directive.

The ngFor directive will iterate over Hobbies array and create the option tag for every option described in the array.

Open the app.component.ts file and add the following code.

import { Component } from '@angular/core';

export class User {
  public name!: string;
  public email!: string;
  public password!: string;
  public hobbies!: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  model = new User();

  Hobbies: string[] = [
    'Acrobatics',
    'Acting',
    'Animation',
    'Astronomy',
    'Baking',
  ];

  constructor() {}

  onSubmit(form: any) {
    console.log(form.value);
  }
}

Define a property class for the form model; it carries the form field’s value and set the model instance with User Class.

Adding Validation in Template-driven Form

Now, we have to add validation in our template-driven angular form and convey a strong message to the user that the form fields are invalid.

Add the required validation in the name field, to access the form control inside the template. We created the name variable and assigned to “ngModel”.

Add the Bootstrap form validation classes. Class validation applies only when the user submits the form and form is invalid.

To show the error message we used the Angular *ngIf directive and checking the input condition on submission and if the form is invalid.

Same way we applied the form validation in other input fields. Open the app.component.html file and add the following code.

<div class="container mt-5">
  <form
    #userForm="ngForm"
    (ngSubmit)="userForm.form.valid && onSubmit(userForm)"
  >
    <div class="form-group mb-3">
      <label>Name</label>
      <input
        type="text"
        name="name"
        class="form-control"
        [(ngModel)]="model.name"
        #name="ngModel"
        [ngClass]="{ 'is-invalid': userForm.submitted && name.invalid }"
        required
      />
      <div class="invalid-feedback" *ngIf="userForm.submitted && name.invalid">
        <p *ngIf="name.invalid">Name is required</p>
      </div>
    </div>

    <div class="form-group mb-3">
      <label>Email</label>
      <input
        type="email"
        class="form-control"
        name="email"
        [(ngModel)]="model.email"
        #email="ngModel"
        [ngClass]="{ 'is-invalid': userForm.submitted && email.invalid }"
        email
        required
      />
      <div *ngIf="userForm.submitted && email.invalid" class="invalid-feedback">
        <div *ngIf="email.invalid">Email is required</div>
      </div>
    </div>

    <div class="form-group mb-3">
      <label>Password</label>
      <input
        type="password"
        class="form-control"
        name="password"
        [(ngModel)]="model.password"
        #password="ngModel"
        [ngClass]="{ 'is-invalid': userForm.submitted && password.invalid }"
        minlength="8"
        required
      />
      <div
        *ngIf="userForm.submitted && password.invalid"
        class="invalid-feedback"
      >
        <div *ngIf="password.invalid">Password is required</div>
      </div>
    </div>

    <div class="form-group mb-3">
      <label>Hobbies</label>
      <select class="form-control" name="hobbies" [(ngModel)]="model.hobbies">
        <option value="">Select an option</option>
        <option *ngFor="let hoby of Hobbies" [value]="hoby">
          {{ hoby }}
        </option>
      </select>
    </div>

    <div class="form-group">
      <button class="btn btn-danger btn-block">Submit</button>
    </div>
  </form>
</div>

Now we have configured Angular and Bootstrap, run the command to open the app in the browser.

ng serve --open

Angular Bootstrap Template Driven Form Validation Example

Conclusion

Finally, we have completed the Angular Forms tutorial, and In this tutorial, we learned how to create Angular form with the template-driven approach.

So far we have learned:

how to implement Bootstrap in Angular and create forms with Bootstrap.

how to work with the ngModel directive to handle the Angular form data.

how to add validation in template-driven forms as well as how to submit a form.

To get the full code of this tutorial visit this GitHub repository.