Ensuring Form Validation in Real Time as Users Input Data in Angular 2

I have successfully implemented form validation using the following code:

import { FormGroup, Validators, FormControl } from "@angular/forms";

Currently, I have disabled the Submit button until the form is filled out correctly. The only indication given to the user regarding the validity of the form is by displaying red text in the input fields when they are not valid.

https://i.sstatic.net/2U7cV.png

I am looking for a way to display error messages to the user indicating what exactly is wrong with their input.

Is there an in-built feature in Angular2 that can show the error message or reason why an input field is invalid? Or do I need to create custom error messages for each field? If custom error messages are required, how can I check each input field, e.g., when the user moves focus away from a specific field, so I can display a message explaining why it was invalid?

I already have a method to display messages; I just need a mechanism to obtain the error messages, i.e., extract text from the form to explain why it's invalid.

Example

Please provide a valid mobile number

Code

REGEX

  ngOnInit() {
        this.personalForm = new FormGroup({
            email : new FormControl(this.auth.user.email,Validators.required ),
            first_name: new FormControl(null,[
                Validators.required,
                Validators.pattern("^[a-zA-Zñáéíóúü']{1,30}$")
            ]),
            middle_name: new FormControl(null,[
                Validators.required,
                Validators.pattern("^[a-zA-Zñáéíóúü']{1,30}$")
            ]),

            last_name: new FormControl(null,[
                Validators.required,
                Validators.pattern("^[a-zA-Zñáéíóúü']{1,30}$")
            ]),

            dob : new FormControl (null, [
                Validators.required,
                Validators.pattern("[1][9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]|[2][0][0-9][0-9]-[0-9][0-9]-[0-9][0-9]")
            ]),
            mobile_phone: new FormControl(null, [
                Validators.required,
                Validators.pattern("[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]|[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]")
            ]),
            home_phone: new FormControl(null, [
                Validators.required,
                Validators.pattern("[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]|[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]")
            ]),

            business_phone: new FormControl(null, [
                Validators.requi...

Valid Boolean / Handle The Form Data

save(model: Personal, isValid: boolean) {
        if (!isValid) {
            console.log('Personal Form is not valid');
            console.log(model, isValid);
        } else {
            console.log('Personal Form is valid');
            console.log(model, isValid);
            let headers = new Headers();
            headers.append('Content-Type', 'application/json');
            return this.http
                .post('http://localhost:4200/api/updateProfile',
                    model,
                    {headers: headers})
                .map((res: Response) => res.json())
                .subscribe((res) => {
                    //do something with the response here
                    console.log(res);
                });
        }
    }

Form

<form [formGroup]="personalForm" novalidate (ngSubmit)="save(personalForm.value, personalForm.valid)">
    <div class="row">
        <div class="col-sm-12 col-md-12 col-lg-12">
            <div class="card card-inverse card-success">
                <div class="card-header">
                    <strong>Personal Information</strong>
                </div>
                <div class="card-block">
                    <div class="row">
                        <div class="form-group col-sm-12 col-md-12">
                            <label for="email">Email</label>
                            <div class="input-group">
                                <span class="input-group-addon"><i class="fa fa-envelope"></i>
          </span>
                                <input type="text" class="form-control" id="email" formControlName="email" placeholder="{{personal.email}}"readonly>
                            </div>
                            <div class="alert alert-danger" *ngIf="!personalForm.controls.email.valid && submitted ">
                                *Email is required.
                            </div>
                        </div>
                    </div>

Answer №1

Overview

If you want to access the FormGroup input fields, you can utilize a specific syntax to reach the controls that have been generated.

this.FormGroupName.get('ControlName').status

This code snippet will either return VALID or INVALID.

In my situation, this is how I achieved it:

Example

First, import the necessary packages:

import {FormGroup, Validators, FormControl } from "@angular/forms";
import {INVALID, VALID} from "@angular/forms/src/model";

Next, create the FormGroup:

personalForm: FormGroup;

Afterwards, create the FormControl:

 ngOnInit() {
        this.personalForm = new FormGroup({
            first_name: new FormControl(null, [
                Validators.required,
                Validators.pattern("^[a-zA-Zñáéíóúü']{1,30}$")
            ]),
   });
}

Add the FormControlName to the form, along with the corresponding function to use when checking for errors.

<input (blur)="firstNameValidate('*First Name Required', 'Use 1-30 letters to spell your name.')" type="text" class="form-control" placeholder="Enter first name" id="first_name" formControlName="first_name">

To check if it is VALID or INVALID,

firstNameValidate(ErrorTitle, ErrorMessage) {
        if (this.personalForm.get('first_name').status == VALID) {
            this.getSuccess("First Name Entered", "First name entered correctly");
        } else {
            this.toastWarning(ErrorTitle, ErrorMessage);
        }
    }

Handling Errors

In my case, I opted to display errors using a toast. By utilizing blur to monitor when a user exits an input field, I trigger the firstNameValidate() function which displays the appropriate toast based on whether the value is VALID or INVALID. Based on the response, one of two functions is executed.

toastWarning(ErrorTitle, ErrorMessage) {
        var toastOptions: ToastOptions = {
            title: ErrorTitle,
            msg: ErrorMessage,
            showClose: true,
            timeout: 7000,
            theme: 'bootstrap',
            onAdd: (toast: ToastData) => {
                console.log('Toast ' + toast.id + ' has been added!');
            },
            onRemove: function(toast: ToastData) {
                console.log('Toast ' + toast.id + ' has been removed!');
            }
        };
            this.toastyService.warning(toastOptions);
        }

    getSuccess(SuccessTitle, SuccessMessage) {
        var toastOptions: ToastOptions = {
            title: SuccessTitle,
            msg: SuccessMessage,
            showClose: true,
            timeout: 5000,
            theme: 'bootstrap',
            onAdd: (toast: ToastData) => {
                console.log('Toast ' + toast.id + ' has been added!');
            },
            onRemove: function(toast: ToastData) {
                console.log('Toast ' + toast.id + ' has been removed!');
            }
        };
        this.toastyService.success(toastOptions);
    }

The end result is that the user will observe the pertinent toast / message,

Success

https://i.sstatic.net/TTsOt.png

Warning

https://i.sstatic.net/tFqLd.png

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for combining two property values to create a unified data table column in Angular 7's data table system (e.g. merging first and last names into one column)

I need to combine the first name and last name of a person into a single "Name" column in my Angular 7 data table. The first name and last name are stored as separate properties. <data-table [items]="userItems" [itemCount]=" ...

When using multiple select tags with *ngFor in Angular, modifying the value of the first select tag will have an

<table id="DataTable" border="1" ALIGN="center"> <tr ALIGN="center"> <th>name</th> <th>address</th> <th>number</th> <th>type</th> </tr> <tr class="tcat" *ngFor ...

Verify if a particular string is present within an array

I am in possession of the key StudentMembers[1].active, and now I must verify if this particular key exists within the following array const array= ["StudentMembers.Active", "StudentMembers.InActive"] What is the method to eliminate the index [1] from Stu ...

Angular has got us covered with its latest feature - combining Async Await with an EventListener

I have been facing this issue for the past day and need help creating a specific scenario: <img [src]="userdp | async" /> In my component.ts file, I want to include only this line: this.userdp = this._userService.getUserDp(); Here is the ...

Firebase Authentication error code "auth/invalid-email" occurs when the email address provided is not in a valid format, triggering the message "The email address is

Currently, I am working on integrating Firebase login and registration functionality into my Angular and Ionic 4 application. Registration of user accounts and password retrieval are functioning properly as I can see the accounts in my Firebase console. Ho ...

Using template expressions to access properties that contain spaces

Here is the code structure that I am working with: "name": { "age": [ { "data": { "how old": "23" } }, One of my JSON keys has a space in it. How can I access this pr ...

The timezone plugin in day.js may sometimes generate an incorrect date

For a while, I've been using dayjs in my angular project to convert timestamps from UTC to localtime. However, after my recent update, this functionality stopped working. This isn't the first issue I've encountered with dayjs, so I decided t ...

Repeated calls to Angular's <img [src]="getImg()"> frequently occur

Can someone help me figure out what's going on here? Recently, I set up a new Angular project and in app.component.html, I have the following code: <img [src]="getDemoImg()"> In app.component.ts: getDemoImg(){ console.log('why so m ...

Dealing with nested models in Angular and Typescript by accessing them as arrays

Attempting to access the child member (which is an array) of a parent interface, but receiving undefined. export class Address { id: number; city: string; state: string; } import { Address } from './address'; export class User { ...

The compiler does not recognize the TSConfig option 'lib' - please review and correct

I have inherited an angular 1 project written in typescript version 1.8.10. However, I am encountering compilation issues with the following error message: Unknown compiler option 'lib' If I remove the "lib" line, a cascade of other errors suc ...

Steps for creating a click event for text within an Ag-Grid cell

Is there a way to open a component when the user clicks on the text of a specific cell, like the Name column in this case? I've tried various Ag-Grid methods but couldn't find any that allow for a cell text click event. I know there is a method f ...

Creating a function in Typescript that accepts an array of strings and generates an output with the strings utilized as keys

I am working on a function that takes an array of strings and generates an object where the strings are used as keys with a value of true assigned to each. Here is the code snippet for that: return keys.reduce((result, key) => { result[key] = true ...

Retrieve elements from a separate pom file

I am looking to organize my web elements by defining them in a separate js file from my test file using Protractor. In my pom.js object, I have set up the following: let web_elements = function() { this.get_login_mail, function() { ...

How can I retrieve properties from a superclass in Typescript/Phaser?

Within my parent class, I have inherited from Phaser.GameObjects.Container. This parent class contains a property called InformationPanel which is of a custom class. The container also has multiple children of type Container. I am attempting to access the ...

Omit the use of "default" when importing a JSON file in Vite+React with Typescript

Each time I attempt to import a JSON file, it seems to enclose the JSON within a "default" object. When trying to access the object, an error message displays: Property 'default' does not exist on type... I have already configured resolveJsonMod ...

Inquiry regarding modules in Javascript/Typescript: export/import and declarations of functions/objects

I'm fresh to the realm of TypeScript and modules. I have here a file/module that has got me puzzled, and I could really use some guidance on deciphering it: export default function MyAdapter (client: Pool): AdapterType { return { async foo ( ...

The property 'dateClick' is not found in the 'CalendarOptions' type in version 6 of fullcalendar

Below is the Angular code snippet I am currently using: calendarOptions: CalendarOptions = { plugins: [ dayGridPlugin, timeGridPlugin, listPlugin ], initialView: 'dayGridMonth', headerToolbar: { left: 'prev today next' ...

Generating an array of elements from a massive disorganized object

I am facing a challenge in TypeScript where I need to convert poorly formatted data from an API into an array of objects. The data is currently structured as one large object, which poses a problem. Here is a snippet of the data: Your data here... The go ...

Any tips on how to personalize the loading animation for single pages using CSS and GIFs?

presentLoading(message) { this.loading = this.loadingCtrl.create({ dismissOnPageChange: false, spinner:'hide', content:`<img class="load" src="assets/dual.gif" />`, }); this.loading.present(); } Hello there! I am working with the ...

Does angular-sortablejs work with angular 5?

I attempted to use angular-sortables in combination with the ng-drag-drop library to sort the list items that are being dragged, but it appears that nothing is happening when I try to use it. Does anyone know if angular-sortables is compatible with Angular ...