Angular 9/8 Reactive Forms with Validation Tutorial by Example

Angular 9/8 Reactive Forms with Validation Tutorial by Example

Reactive forms are one approach (alongside with the template-driven approach) of working with forms in Angular 9.

In this tutorial, we'll build a login form example with validation using the reactive or the model-driven approach.

Prerequisites for Working with Reactive Forms in Angular 9

You need to have Node.js and npm installed on your system.

You also need Angular CLI 9 installed otherwise, you can simply run the npm install -g @angular/cli command to install it.

Generating a New Angular 9 Project

Let's start our tutorial by generating a project from scratch. You can skip this part if you already have a project.

Open a new terminal and run this command:

$ ng new angular-login-demo

You will be asked if Would you like to add Angular routing? Enter y and Which stylesheet format would you like to use? Choose CSS.

The CLI will generate the necessary source and configuration files and install the npm dependencies. You'll also have routing setup without further intervention from you. You only need to add your components in the routes array in the src/app/app-routing.module.ts file which is the root routing module of our application.

Generating Components, Interface, Service and Router Guard

Let's now generate the different artifacts needed in our project. We'll need a couple of components, a service, an interface and a Router guard.

Head back to your terminal and navigate in the root folder of your project:

$ cd angular-login-demo

Generating Login and Admin Components

Next, use the ng generate command to generate the components:

$ ng g c login
$ ng g c admin

We generate two LoginComponent and AdminComponent components.

The login component will contain a model-driven (reactive) form for submitting the user's email and password.

The admin component will be protected from public access. Only logged in users will be able to access it and will contain a logout button permitting the user to log out.

You need to add these components to the routing module. Open the src/app/app-routing.module.ts file and the following changes:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { LoginComponent } from './login/login.component';
import { AdminComponent } from './admin/admin.component';

const routes: Routes = [
  { path: '', pathMatch: 'full', redirectTo: 'login'},
  { path: 'login', component: LoginComponent },
  { path: 'admin', component: AdminComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

We add three routes, one for redirecting the empty path to the login path, the login path and the admin path. Now, when you visit the http://127.0.0.1:4200/ address you'll be redirected to http://127.0.0.1:4200/login.

If you serve your application at this point, you'll get the following page:

Angular 7/8 Login Form Example

Let's remove this default HTML code. Open the src/app/app.component.html file and remove everything but leave <router-outlet>:

<router-outlet></router-outlet>

Generating the User Model/Interface

We'll be working with a user model so we need to generate a User interface. In your terminal, run the following command:

$ ng g interface user

Open the src/app/user.ts file and update it accordingly:

export  interface  User {
    email: string;
    password: string;
}

Our model is comprised of an email and password.

Generating an Angular Authentication Service

Let's now create an Angular service that encapsulates the methods that we'll be calling in our components to enable users to login and logout. In your terminal:

$ ng g service auth

Open the src/app/auth.service.ts file and update it accordingly:

import { Injectable } from '@angular/core';
import { User } from './user';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor() { }

  public login(userInfo: User){
    localStorage.setItem('ACCESS_TOKEN', "access_token");
  }

  public isLoggedIn(){
    return localStorage.getItem('ACCESS_TOKEN') !== null;

  }

  public logout(){
    localStorage.removeItem('ACCESS_TOKEN');
  }
}

This is a incomplete authentication service. For a real world and complete implementation, check out Angular 7/8 Tutorial: Using Angular HttpClient with Node & Express.js - Example POST Requests.

Creating a Router Guard

Let's now create a Router guard that will be used for securing the admin component. In your terminal, run this command:

$ ng generate guard auth

Open the src/app/auth.guard.ts file and update it accordingly:

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService){}
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

      return this.authService.isLoggedIn();

  }
}

We import AuthService and inject it via the class constructor then in the canActivate() method, we call and return the isLoggedIn() method.

The canActivate() method returns true if the isLoggedIn() methods returns true i.e if the user is logged in.

If the canActivate() method returns true the route which has this guard applied can be accessed by the user.

Next, you need to apply this guard to the route you want to protect. Open the src/app/app-routing.module.ts file and update it accordingly:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { LoginComponent } from './login/login.component';
import { AdminComponent } from './admin/admin.component';
import { AuthGuard } from './auth.guard';


const routes: Routes = [
  { path: '', pathMatch: 'full', redirectTo: 'login'},
  { path: 'login', component: LoginComponent },
  { path: 'admin', component: AdminComponent, canActivate: [AuthGuard] }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

We use the canActivate array of the admin route to apply AuthGuard to the route which protects it from users that are not logged in.

Creating the Login Form using Angular 9 Reactive Forms

Before using reactive forms in Angular 9 we need to import FormsModule and ReactiveFormsModule in the application module.

Open the src/app/app.module.ts file and update it accordingly:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule} from '@angular/forms';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
import { AdminComponent } from './admin/admin.component';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    AdminComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

We can now use reactive forms in our application!

Open the src/app/login.component.ts file and import:

  • FormBuilder, FormGroup, Validators symbols that are used to create Angular reactive forms,
  • Router for routing,
  • AuthService and the User model.
import { FormBuilder, FormGroup, Validators } from  '@angular/forms';
import { Router } from  '@angular/router';
import { User } from  '../user';
import { AuthService } from  '../auth.service';

Next, inject the FormBuilder, Router and AuthService via the service constructor:

export class LoginComponent implements OnInit {

  constructor(private authService: AuthService, private router: Router, private formBuilder: FormBuilder ) { }

  ngOnInit() {
  }
}

Next, add these service variables:

  loginForm: FormGroup;
  isSubmitted  =  false;

Next, in the ngOnInit() life-cycle event, create the form:

ngOnInit() {
    this.loginForm  =  this.formBuilder.group({
        email: ['', Validators.required],
        password: ['', Validators.required]
    });
}

Next, add a get property to make easy to access the form controls on the HTML form:

get formControls() { return this.loginForm.controls; }

Finally, add the login() method:

  login(){
    console.log(this.loginForm.value);
    this.isSubmitted = true;
    if(this.loginForm.invalid){
      return;
    }
    this.authService.login(this.loginForm.value);
    this.router.navigateByUrl('/admin');
  }

Let's now create the HTML form. Open the src/app/login.component.html file and the following content:

<h1 style="text-align:center">
  Angular 9 Login Example
</h1>
<div class="login">
  <h2 class="login-header">Log in</h2>
  <form [formGroup]="loginForm" class="login-container" (ngSubmit)="login()">

    <p [ngClass]="{ 'has-error': isSubmitted && formControls.email.errors }">
      <input type="email" placeholder="Email" formControlName="email">
    </p>

    <div *ngIf="isSubmitted && formControls.email.errors" class="help-block">
      <div *ngIf="formControls.email.errors.required">Email is required</div>
    </div>

    <p [ngClass]="{ 'has-error': isSubmitted && formControls.password.errors }">
      <input type="password" placeholder="Password" formControlName="password">
    </p>

    <div *ngIf="isSubmitted && formControls.password.errors" class="help-block">
      <div *ngIf="formControls.password.errors.required">Password is required</div>
    </div>

    <p>
      <input type="submit" value="Log in">
    </p>
  </form>
</div>

For styling the form we'll be using this codepen example.

Open the src/styles.css and add:

@import  url(https://fonts.googleapis.com/css?family=Open+Sans:400,700);
body {
    background: #456;
    font-family: 'Open Sans', sans-serif;
}

Next, open the src/app/login.component.css file and these styles:

This is the screenshot of our reactive login form:

Angular Reactive login form

Also, add this CSS style for error class:

.has-error input[type="email"],
.has-error input[type="password"] {
    border-color: rgb(216, 12, 12);
    color: rgb(230, 14, 14);
}

This is a screenshot of the form when not valid:

Angular 7/8 reactive form invalid

Implementing the Admin Component

Open the src/app/admin.component.ts file and add:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../auth.service';

@Component({
  selector: 'app-admin',
  templateUrl: './admin.component.html',
  styleUrls: ['./admin.component.css']
})
export class AdminComponent implements OnInit {

  constructor(private authService: AuthService, private router: Router) { }

  ngOnInit() {
  }

  logout(){
    this.authService.logout();
    this.router.navigateByUrl('/login');
  }

}

Next, open the src/app/admin.component.html file and add:

<div style="text-align:center">
  <h1>
    Welcome Super Admin!
  </h1>
  <p>
    <button (click)="logout()">
      Logout
    </button>
  </p>
  <img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>

Finally, open the src/app/admin.component.css file and add:

button{
    background: rgb(1, 29, 51);
    border-color: transparent;
    color: #fff;
    cursor: pointer;
}

This is the screenshot of our admin page:

Angular 9/8 form example

You can log out from the admin page and you will be redirected to the login form.

Conclusion

We reached the end of this tutorial in which we have created a login from with Angular 9 reactive forms. We've also seen how to do form validation.



Angular 9 Components: Input and Output
Angular 13 selectors
Picture-in-Picture with JavaScript and Angular 10
Jasmine Unit Testing for Angular 12
Angular 9 Tutorial By Example: REST CRUD APIs & HTTP GET Requests with HttpClient
Angular 10/9 Elements Tutorial by Example: Building Web Components
Angular 10/9 Router Tutorial: Learn Routing & Navigation by Example
Angular 10/9 Router CanActivate Guards and UrlTree Parsed Routes
Angular 10/9 JWT Authentication Tutorial with Example
Style Angular 10/9 Components with CSS and ngStyle/ngClass Directives
Upload Images In TypeScript/Node & Angular 9/Ionic 5: Working with Imports, Decorators, Async/Await and FormData
Angular 9/Ionic 5 Chat App: Unsubscribe from RxJS Subjects, OnDestroy/OnInit and ChangeDetectorRef
Adding UI Guards, Auto-Scrolling, Auth State, Typing Indicators and File Attachments with FileReader to your Angular 9/Ionic 5 Chat App
Private Chat Rooms in Angular 9/Ionic 5: Working with TypeScript Strings, Arrays, Promises, and RxJS Behavior/Replay Subjects
Building a Chat App with TypeScript/Node.js, Ionic 5/Angular 9 & PubNub/Chatkit
Chat Read Cursors with Angular 9/Ionic 5 Chat App: Working with TypeScript Variables/Methods & Textarea Keydown/Focusin Events
Add JWT REST API Authentication to Your Node.js/TypeScript Backend with TypeORM and SQLite3 Database
Building Chat App Frontend UI with JWT Auth Using Ionic 5/Angular 9
Install Angular 10 CLI with NPM and Create a New Example App with Routing
Styling An Angular 10 Example App with Bootstrap 4 Navbar, Jumbotron, Tables, Forms and Cards
Integrate Bootstrap 4/jQuery with Angular 10 and Styling the UI With Navbar and Table CSS Classes
Angular 10/9 Tutorial and Example: Build your First Angular App
Angular 9/8 ngIf Tutorial & Example
Angular 10 New Features
Create New Angular 9 Workspace and Application: Using Build and Serve
Angular 10 Release Date: Angular 10 Will Focus on Ivy Artifacts and Libraries Support
HTML5 Download Attribute with TypeScript and Angular 9
Angular 9.1+ Local Direction Query API: getLocaleDirection Example
Angular 9.1 displayBlock CLI Component Generator Option by Example
Angular 9 Basics Tutorial by Example
Angular 9/8 ngFor Directive: Render Arrays with ngFor by Example
Responsive Image Breakpoints Example with CDK's BreakpointObserver in Angular 9/8
Angular 9/8 DOM Queries: ViewChild and ViewChildren Example
The Angular 9/8 Router: Route Parameters with Snapshot and ParamMap by Example
Angular 9/8 Nested Routing and Child Routes by Example
Angular 9 Examples: 2 Ways To Display A Component (Selector & Router)
Angular 9/8 Tutorial: Http POST to Node/Express.js Example
Angular 9/8 Feature and Root Modules by Example
Angular 9/8 with PHP: Consuming a RESTful CRUD API with HttpClient and Forms
Angular 9/8 with PHP and MySQL Database: REST CRUD Example & Tutorial
Unit Testing Angular 9/8 Apps Tutorial with Jasmine & Karma by Example
Angular 9 Web Components: Custom Elements & Shadow DOM
Angular 9 Renderer2 with Directives Tutorial by Example
Build Progressive Web Apps (PWA) with Angular 9/8 Tutorial and Example
Angular 9 Internationalization/Localization with ngx-translate Tutorial and Example
Create Angular 9 Calendar with ngx-bootstrap datepicker Example and Tutorial
Multiple File Upload with Angular 9 FormData and PHP by Example
Angular 9/8 Reactive Forms with Validation Tutorial by Example
Angular 9/8 Template Forms Tutorial: Example Authentication Form (ngModel/ngForm/ngSubmit)
Angular 9/8 JAMStack By Example
Angular HttpClient v9/8 — Building a Service for Sending API Calls and Fetching Data
Build an Angular 9/8 CRUD Example & Tutorial
Styling An Angular 9/8/7 Example App with Bootstrap 4 Navbar, Jumbotron, Tables, Forms and Cards
Angular 8/7 Tutorial By Example: (REST API, HttpClient GET, Components, Services & ngFor)

✋If you have any questions about this article, ask them in our GitHub Discussions 👈 community. You can also Gitter

✋ Want to master Angular 14? Read our angular tutorial and join our #DailyAngularChallenge where we learn to build components, directives, services, pipes and complete web, mobile, and desktop applications with latest Angular version.

✋ Make sure to join our Angular 14 Dev Community 👈 to discuss anything related to Angular development.

❤️ Like our page and subscribe to our feed for updates!