Beginner in Angular: Template-Driven Forms in Angular

Tanvi shah
5 min readApr 27, 2020

--

We create forms to accept user inputs. A form is created for various purposes such as login, sign up, submit a help request.. A form in combination of HTML control contains input elements, buttons, check boxes and radio buttons.

To work with user inputs, Angular provides us different types of Forms:

  • Template-Driven Forms
  • Reactive Forms

Template Driven Forms:

Template driven forms are forms where we write logic, validation, control.. in the template part of the code, HTML code. Template driven forms are normal forms on which we use Angular directives to enable Angular features such as two-way data binding, change notification, validations and so on.

Enabling Template Driven forms:

To use the template driven form, we need to explicitly import {FormsModule} in our application module from @angular/forms and pass it in imports array.

import {FormsModule} from @angular/forms;@Component({..})

@NgModule({
declarations: [App],
imports: [BrowserModule, FormsModule],
bootstrap: [App]
})
export class AppModule{}

Model Class:

We are going to create a template driven form for Login operation. To model Login operation, we will create a model class which will contain login properties with no methods.

To create Model class:

ng g class models/login.model

login.model.ts:

export class Login {
constructor (
public email: string,
public password: string,
public rememberpassword? : boolean
) {}
}

When there are more model classes in use, we can create a service to increase
modularity and reusability with a well defined purpose and connect all of them.

Model object:

This is written in component class i.e. AppComponent. The object of Login class will act as model of the form which we will bind to it.

model: Login;
constructor () {
this.model = new Login(‘tanvi@google.com’,’password123',true);
}

ngModel:

Having model object, now we will bind it to the input elements of the form as Angular template form elements. We can bind email property of model object to email input of the form as shown:

<input type=”text”
[(ngModel)]=’model.email’
name=’email’
class=”form-control” required>

Here, there are two important properties set: name and ngModel.

To set the name is necessary because it works as the key in FormGroup array for a particular element.

ngModel is used to bind input element with model object. There are three options to bind input element with model object:

  • ngModel: In this,ngModel will use name attribute to create key in ngForm object. In it, input element is not set with any initial value i.e. ngModel.
  • [ngModel]: It is used to create one-way binding. When ngModel is set as property binding, it will set initial value of input element with model object i.e. [ngModel]=’model.email’.
  • [(ngModel)]”: It is used to create two-way data binding in between model object and input element. This option will set initial value of element and whenever element is updated, it will update model object also i.e. [(ngModel)]=’model.email’.

ngForm:

ngForm directive is used to bind HTML form such that it would work as template driven form. It is an instance of Form Group which represents Form Control that gives access to additional features like ngSubmit.

If ngModel and name attribute is set for a form, ngForm works as:

  • It monitors properties of form elements.
  • It monitors validity of form elements.
  • It raises notification if value changes of form elements.
  • It also have valid property which is set to true if all the form elements validity is true.
<form nonvalidate #loginform=’ngForm’>
</form>

nonvalidate attribute is used to disable browser’s native form validation. It is used when we want to do our own custom validation.

ngSubmit:

To submit template-driven form, we need to use ngSubmit event on the form:

<form nonvalidate #loginform=’ngForm’ (ngSubmit)=’onSubmit(loginform)’>
..
</form>

Now, we can bind ngSubmit event to a function in the component class:

onSubmit(loginform) {
console.log(loginform.value);
console.log(loginform.status);
}

Template driven form has value and status properties. The value is an object, which contains all form elements as properties and status is Boolean, which will be true if form is valid.

We can also disable Submit button if form is invalid by setting [disabled] property of button to form.invalid.

Template-driven Form:

HTML file:

<form nonvalidate #loginform=’ngForm’
(ngSubmit)=’onSubmit(loginform)’>
<div class=”form-group”>
<label for=”email”>Email</label>
<input type=”text” [(ngModel)]=’model.email’ name=’email’ class=”form-control”
required>
</div>
<div class=”form-group”>
<label for=”password”>Password</label>
<input type=”password” [(ngModel)]=’model.password’ name=’password’ minlength=”4" class=”form-control” required>
</div>
<div class=”form-check”>
<input type=”checkbox” [(ngModel)]=’model.rememberpassword’ name=’rpassword’ class=”form-check-input” required>
<label class=”form-check-label” for=”rpassword”>Remember Password</label>
</div>
<button [disabled]=’loginform.invalid’ type=”submit” class=”btn btn-success”>Login
</button>
</form>

Class File:

import { Component } from ‘@angular/core’;
import { Login } from ‘./login’;
@Component({
selector: ‘app-root’,
templateUrl: ‘./app.component.html’,
styleUrls: [‘./app.component.css’]
})
export class AppComponent{
model: Login;
constructor () {
this.model = new Login(‘tanvi@google.com’,’password123',true);
}
onSubmit(loginform) {
console.log(loginform.value);
console.log(loginform.status);
}
}

Handling Validations:

  • required: It is used to enforce the user that the input must be filled. Again, it is necessary to be sure that the form has been touched before validating it(Point 3).
  • Maxlength, Minlength and Pattern: The Maxlength and Minlength is used to used to enforce maximum and minimum numbers to be accepted as input respectively. Pattern attribute is mostly used for regular expression validation on input. Then, we can individually check on errors if needed.
  • Angular template driven form tracks state of a control and updates CSS class associated with it…

When we use ngModel in the form, it performs following tasks:

  • Two-way data binding.
  • Find whether user touched the control.
  • Track states of the control.
  • Update validation CSS associated with the controls.

Controls:

  • Control visited: true ng-touched, false ng-untouched
  • Control value changed: true ng-dirty, false ng-pristine
  • Control value valid: true ng-valid, false ng-invalid

Adding custom CSS to component:

.ng-valid[required], ng.valid.required {
border-left: 5px solid #42A948;
}
.ng-invalid:not(form) {
border-left: 5px solid #a94442;
}

Adding changes in form:

Using combination of Angular template driven form validation and CSS classes, we can show validation error message. We have to assign ngModel to temp reference variable to track the changes and then applying validation.

<form nonvalidate #loginform=’ngForm’ (ngSubmit)=’onSubmit(loginform)’><div class=”form-group”>
<label for=”email”>Email</label>
<input type=”text” [(ngModel)]=’model.email’ name=’email’ class=”form-control” #email=’ngModel’ required>
</div>
<div [hidden]=”email.valid | email.pristine” class=”alert alert danger”>
Email is required
</div>
<div class=”form-group”>
<label for=”password”>Password</label>
<input type=”password” [(ngModel)]=’model.password’ name=’password’ minlength=”4" #password=”ngModel” class=”form-control” required>
</div>
<div [hidden]=”password.valid | password.pristine” class=”alert alert-danger”>
Password is invalid
</div>
<div class=”form-check”>
<input type=”checkbox” [(ngModel)]=’model.rememberpassword’ name=’rpassword’ class=”form-check-input” required>
<label class=”form-check-label” for=”rpassword”>Remember Password</label>
</div>
<button [disabled]=’loginform.invalid’ type=”submit” class=”btn btn-success”>Login
</button>
</form>

Reset the Form:

There may be requirement to reset the form and bind it with new model object. Angular template driven form provides API for this also. We can use reset() method ngForm to reset the form.

HTML file:

<button (click)=’newLogin();loginform.reset()’ class=”btn btn-warning”>Reset</button>

On click event of button, we call two functions:

  • newLogin function
  • reset method of the form.

Here, newLogin() is the new model object which is added in the class file of component.

Class file:

newLogin() {
this.model = new Login(‘kinju@google.com’,’ password456', true);
}

Thus, we have created template-driven form with validation. If you find it helpful, please support. Thank you.

--

--

Tanvi shah

Women Techmakers Team - WTM Baroda | GDG Baroda | Google Local Guide | Public Speaker | Technical and Lifestyle Blogger | Web Developer