Verify Angular Reactive Form by clicking the button

Currently, I have a form set up using the FormBuilder to create it. However, my main concern is ensuring that validation only occurs upon clicking the button.

Here is an excerpt of the HTML code:

<input id="user-name" name="userName" placeholder="Enter Username" formControlName="username" class="form-control" />
<label class="form-label" for="user-name">Username</label>

<div class="text-danger" *ngIf="loginForm.controls['username'].touched && loginForm.controls['username'].errors?.['required']">Please enter the username</div>

Below shows part of the .ts file code:

constructor(private formBuilder: FormBuilder) {}

ngOnInit() {
  this.generateForm();
}

generateForm() {
  this.loginForm = this.formBuilder.group({
    username: [null, Validators.compose([Validators.required])],
    password: [null, Validators.compose([Validators.required])],
  });
}

Instead of triggering validations automatically, I want them to activate when the button is clicked, displaying any errors afterwards.

If you have any suggestions or solutions, please share as they would greatly assist me. Thank you.

Answer №1

  1. Set a flag named submitted.
submitted = true;
  1. Include the (ngSubmit) event and update the submitted flag to true. This will indicate that the form has been submitted.
<form [formGroup]="loginForm" (ngSubmit)="submitted = true">
  
  ...

  <button>Submit</button>
</form>
  1. Display an error message when the submitted flag is set to true.
<div
  class="text-danger"
  *ngIf="submitted && loginForm.controls['username'].errors?.['required']"
>
  Please enter the username
</div>

Check out the demonstration on StackBlitz


Extra Information

If you notice that after submitting the form with an empty field, the error message appears (expected behavior). When you fill in the field, the error message disappears (expected behavior). However, if you try to clear the field (make it blank), the error message reappears (unexpected behavior).

This issue occurs because the submitted flag remains true once the form is submitted. To address this, you can subscribe to the form's valueChanges event and reset the submitted flag when the user inputs data after a previous submission.

import { debounceTime } from 'rxjs';

this.loginForm.valueChanges.pipe(debounceTime(500)).subscribe((_) => {
  if (this.submitted) this.submitted = false;
});

Improved demonstration on StackBlitz

Answer №2

Hey there! A handy tip for you is to create a function that will mark all the controls on your form as touched and trigger it when the form is invalid.

submitForm(): void {
    if (this.loginForm.invalid) {
        this.markFormGroupTouched(this.loginForm);
        return;
    }
    // Actions to submit the form
}

markFormGroupTouched(formGroup: FormGroup): void {
    ( Object as any).values(formGroup.controls).forEach(control => {
        control.markAsTouched();
        if (control.controls) {
            this.markFormGroupTouched(control);
        }
    });
}

I trust this advice will be of assistance to you. Best regards!

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

What is the best way to trigger a function when a button is enabled in Angular 8?

Here is a portion of my sign-in.component.html file. I have created a function in the corresponding sign-in.component.ts file that I want to trigger when the button below becomes enabled. Here is an example of what I am trying to achieve: <div class= ...

In Typescript, an index signature parameter can only be of type 'string' or 'number'

I'm facing an issue with a generic type that defaults to string: interface EntityState<typeOfID = string> { entities: { [ id: typeOfID]: any }; } The error I receive is: An index signature parameter type must be either 'string' or ...

Creating a function in Typescript to extend a generic builder type with new methods

Looking to address the warnings associated with buildChainableHTML. Check out this TS Playground Link Is there a way to both: a) Address the language server's concerns without resorting to workarounds (such as !,as, ?)? b) Dodge using type HTMLChain ...

Exploring the application of keyof with object structures instead of defined types

Looking to create a new type based on the keys of another object in TypeScript. Successfully achieved this through type inference. However, using an explicit type Record<string, something> results in keyof returning string instead of a union of the ...

Tips for verifying the presence of a specific value within an array of union types

Given an array of a specific union type, I am trying to determine if a string from a larger set that includes the union type is present in the array during runtime: const validOptions: ("foo" | "bar")[] = ["foo", "bar"] type IArrType = typeof validOptions ...

Having trouble loading the Phoenix JS library using SystemJS in an Angular 2 application

After completing the Angular2 quickstart typescript tutorial, which can be found here, I am now attempting to integrate the phoenix.js package in order to connect to my Elixir Phoenix channels. I have added the phoenix package from this source to my packa ...

Increasing the number of service providers in Angular2-4 directives

Is there a way to apply both * to a string? Below is the code snippet I am working with: <a class="sidenav-anchor" *ngIf="!item.hasSubItems()" md-list-item md-ripple [routerLink]="[item.route]" routerLinkActive="active" [routerLinkActiveOptions]="{ex ...

Encountered issues while trying to utilize wasm function within Vue framework

When attempting to integrate wasm with Vue, I encountered a frustrating issue where the startQuorum function in my wasm file could not be located. import { Go } from './wasm_exec' import quorumWasmUrl from './lib.wasm' export const sta ...

Tips for customizing the appearance of date and time formats

Does anyone know how to retrieve this specific time format using Angular2 TypeScript? 2016-9-25T05:10:04.106Z I've tried searching online but couldn't find a straightforward solution. When attempting this in TypeScript, the following results a ...

Prisma: Utilizing the include option will retrieve exclusively the subobject fields

I created a function to filter the table building and optionally pass a Prisma.BuildingInclude object to return subobjects. async describeEntity(filter: Filter, include?: Prisma.BuildingInclude): Promise<CCResponse> { try { const entity = await ...

Newbie seeking help with Angular Services

I'm struggling to avoid duplicating code by using a service. How can I refactor this into a service and then utilize it in the component? Any assistance would be greatly appreciated. function navigateToLink(myRecords) { this.targetLink = this.data.l ...

Tips for adding a mat-error to a mat-input-field on-the-fly

To handle user input exceeding maxLength and dynamically add < mat-error > to the DOM in case of an error, I have implemented an attribute directive that enforces the character limit on input fields. This directive is used across multiple files in th ...

Having trouble with ngx-pagination's next page button not responding when clicked?

I am experiencing issues with pagination. The next page button does not function as expected, and clicking on the page number also does not work. Below is the code snippet and a Demo link for your reference. HTML <table mat-table [dataSou ...

Accessing clipboard contents upon button click using TypeScript

Seeking assistance with retrieving data from the clipboard in TypeScript after clicking on a button. Please provide guidance. Thank you! ...

Identifying Errors in Meteor's Data Publications

I am currently working on a web application using Meteor and AngularJS 2. Take a look at the publication function below: Meteor.publish('abc', function () { // For throwing the meteor error according to the condition if(!this.userId) throw new ...

deleting the existing marker before placing a new marker on the Mapbox

Upon the map loading with GeoJson data, I have implemented code to display markers at specified locations. It works flawlessly, but I am seeking a way to remove previous markers when new ones are added. What adjustments should be made for this desired func ...

Session is not functioning properly as anticipated

import * as express from 'express'; import * as session from 'express-session'; import * as bodyParser from 'body-parser'; const app: express.Express = express(); app.use(bodyParser.json()); app.use(session({ secret: &apos ...

Triggering Backbutton actions in Ionic 3Just a heads-up

I need to capture the back button event before it triggers. Once the listener is activated, the back signal has already been sent. This is my approach so far: document.addEventListener("backbutton", () => { console.log("[WARN] Back button pres ...

Facing a Bad Request error while trying to submit a Django Rest Framework Post request that appears to be valid, but is requiring a

Currently, I am in the process of creating a new instance of the SearchNeighborhood object and establishing a connection with an already existing SearchCity object through a POST request. The models I have set up are as follows: class SearchCity(models.M ...

Creating a unified environment variable for Angular 2 and ASP.NET Core MVC: A comprehensive guide

In my ASP.NET Core MVC project, I am utilizing an Angular 2 application. Both the Angular 2 app and the Startup.cs file contain code that is specific to different environments. For example, using http://localhost as the web service URL during development ...