Guide on Validating Several Email Addresses in a React Form using Angular 4

I need to input 50 email addresses with the same domain name (gmail.com).

Currently, I am using a Reactive form but the code I have implemented is not working as expected.

https://stackblitz.com/edit/angular-wfwfow

If anyone could assist me with this, I would greatly appreciate it.

emailPattern = "[a-zA-Z0-9_.+-,;]+@(?:(?:[a-zA-Z0-9-]+\.,;)?[a-zA-Z]+\.,;)?(gmail)\.com";

 ngOnInit() {
        this.accountingForm = this.fb.group({
            'day' : [null, Validators.required], 
            'email': ['',
                Validators.compose([
                    Validators.required,Validators.pattern(this.emailPattern),this.commaSepEmail
                ])
            ]
        });
    }
    commaSepEmail = (control: AbstractControl): { [key: string]: any } | null => {
        console.log("This is value:" + control.value);
        if (!_.isEmpty(control.value)){
            var emails= control.value.split(',');
            const forbidden = emails.some((email:any) => Validators.email(new FormControl(email)));
        console.log(forbidden);
        return forbidden ? { 'email': { value: control.value.trim() } } : null;
        }
    };
<form [formGroup]="accountingForm" (ngSubmit)="generateSOR(accountingForm.value)">
    <input formControlName="email" [pattern]="emailPattern" placeholder="Email Address">
    <button type="submit" mat-raised-button class="mat-primary" [disabled]="!accountingForm.valid">Generate</button>
    </form>

Answer №1

This script is designed to validate a comma-separated list of email addresses without any spaces in between. The presence of a trailing comma is acceptable. For instance:

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="73191c1633161e121a1f5d101c">[email protected]</a>,<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9cf6f5fafae5dcfff3f7f9b2ecf9fdef">[email protected]</a>
. This is equivalent to
<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a7cdc8c2e7c2cac6cecb89c4c8">[email protected]</a>,<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ef8586898996af8c80848ac19f8a8e9c">[email protected]</a>,
. Note that the final comma does not affect the validation. Additionally, there should be no spaces present.

 sendEmailForm: FormGroup;

  emailList: string [];

  ngOnInit(): void {
    this.emailList = [];
    const toAddress = new FormControl('', [
      Validators.required,
      Validators.pattern(/^([\w+-.%]+@[\w-.]+\.[A-Za-z]{2,4},?)+$/)
    ]);

    this.sendEmailForm = new FormGroup({
      toAddress: toAddress
    });
  }
  extractEmailList(e){
    this.emailList = [];
    if(this.sendEmailForm.valid) {     
      let emails = e.split(',');
      emails.forEach(email => {
        if(email && email.length > 0) {
          this.emailList.push(email);
        }
      });
    }
    console.log(this.emailList);
  }

In the view, you can implement validations as shown below.

<form [formGroup]="sendEmailForm" (ngSubmit)="onSubmit($event)">
    <div class="form-group required">
      <span class="label label-primary">Email(s):</span>
      <input
      (ngModelChange)="extractEmailList($event)"
        type="text"
        [formControl]="sendEmailForm.controls['toAddress']"            
        value=""
        maxlength="150"
        name="toAddress"
        class="form-control"
      />
    </div>
    <small
    *ngIf="sendEmailForm.controls['toAddress'].hasError('required') && sendEmailForm.controls['toAddress'].touched"
    class="form-error-msg">
    Valid email is required to send an invitation.
  </small>
    <small
    *ngIf="sendEmailForm.controls['toAddress'].hasError('pattern') && sendEmailForm.controls['toAddress'].touched"
    class="form-error-msg">
    Please enter comma separated list of valid email addresses without spaces in between. No comma is required after last email.
  </small>
      <button type="submit" [disabled]="!sendEmailForm.valid" class="btn btn-primary btn-simple" >Invite</button>
      <small class="form-error-msg">{{emailList.length}} email(s) will be sent.</small>
  </form>

In your onSubmit() method, you can retrieve values from the emailList directly, eliminating the need to fetch them from the form.

Answer №2

After analyzing the problem with the disabled button, I have identified a potential solution. Instead of utilizing a string format for the emailPattern, consider switching to regex format.

Modify your code from:

emailPattern = "[a-zA-Z0-9_.+-,;]+@(?:(?:[a-zA-Z0-9-]+\.,;)?[a-zA-Z]+\.,;)?(gmail)\.com";

To:

emailPattern = /[a-zA-Z0-9_.+-,;]+@(?:(?:[a-zA-Z0-9-]+\.,;)?[a-zA-Z]+\.,;)?(gmail)\.com/;

This adjustment should rectify the issue. You may need to refine the regex pattern further to align with your specific requirements, but it will address the button's disabled status.

In my experience, using regex expressions over strings whenever feasible is preferred as they tend to be more readable and efficient.

Answer №3

All the email validation logic is contained within the emailValidator function, which handles individual email validation as well as enforcing a maximum number of emails. To integrate this into a form, add the following code to the initialization:

recipients: [null, [multipleEmailValidator(20)]],

Implementation example:

import { AbstractControl, ValidatorFn } from '@angular/forms';

export function multipleEmailValidator(max: number): ValidatorFn {
  return (control: AbstractControl): { [key: string]: any } | null => {
    let emails = control.value ? control.value.split(',') : [];
    const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
    const invalidEmails = emails.filter(email => !emailPattern.test(email.trim()));
    if (invalidEmails.length) {
      return invalidEmails.length ? { 'invalidEmail': { value: invalidEmails } } : null;
    } else {
      emails = emails.filter(email => email.trim());
      return emails.length > max ? { 'maxEmails': { value: emails.length } } : null;
    }
  };
}

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

Node Package Manager (NPM): Easily Importing Files from a Package

Is there a way to customize the file import paths within a package? I am working with a UI kit package for our internal project and after building with Webpack, my project structure looks like this: - dist - components - index.d.ts - index.js Prior ...

The power of negative multiplication in TypeScript and React

I am working with a state variable called sortDirection const [sortDirection, setSortDirection] = useState<1 | -1>(1); My goal is to allow a button to toggle the state variable like this setSortDirection(sortDirection * -1); However, I encounter a ...

Tips for eliminating the draggable item's shadow in Angular

Is there a way to remove the shadow seen under the backdrop when dragging an item in the Bootstrap modal dialog? In the image provided, I am trying to drag the "Personal Details" button..https://i.stack.imgur.com/uSNWD.png ...

An issue with the "req" parameter in Middleware.ts: - No compatible overload found for this call

Currently, I am utilizing the following dependencies: "next": "14.1.0", "next-auth": "^5.0.0-beta.11", "next-themes": "^0.2.1", In my project directory's root, there exists a file named midd ...

Updating Previous and Next links in an Angular Table following row deletions: A step-by-step guide

I need to implement a feature where row elements can be deleted by enabling checkboxes on the rows and clicking the Delete button. Although I am able to successfully delete items from the table upon clicking the Delete button, I am facing challenges in upd ...

Unleashed Breakpoint Mystery in Ionic 5 Angular with VSCode

I recently upgraded my Ionic 5 Angular 12 app from Ionic 4 Angular 8. The application is working well and remains stable, but I have encountered some issues while debugging. Firstly, when I use the launch.json file in Visual Studio Code to run the app, it ...

Set up and run a SpringBoot + Angular web application on an external IIS server

When it comes to running a Spring Boot application locally, it's as simple as running it with the spring-boot:run command or executing the main class of the project. However, deploying the same application on an IIS Server can be a bit more challengin ...

Is there a way to incorporate timeouts when waiting for a response in Axios using Typescript?

Can someone assist me in adjusting my approach to waiting for an axios response? I'm currently sending a request to a WebService and need to wait for the response before capturing the return and calling another method. I attempted to utilize async/aw ...

Awaiting the completion of Promises within a for-loop (Typescript)

I'm struggling with a for-loop and promises in my angular2 project. I have multiple methods that return promises, and after these promises are resolved, I want to populate an array in the class using Promise.all(variable).then(function(result){....... ...

What is the reason behind the input value becoming empty after a reset?

Currently, I am working with an input element reference: @ViewChild("inputSearch", { static: false }) This is how the template looks like: <input tabindex="0" type="text" (keydown)="keydownInputSearch($event)" #inputSearch autocomplete="off" ...

Encountering the ExpressionChangedAfterItHasBeenCheckedError error during Karma testing

Testing out some functionality in one of my components has led me to face an issue. I have set up an observable that is connected to the paramMap of the ActivatedRoute to retrieve a guid from the URL. This data is then processed using switchMap and assigne ...

Typescript: The type 'Observable<{}>' cannot be assigned to the type 'Observable'

I'm encountering an issue with the Observable type, any thoughts on how to resolve it? import { PostModel } from '../model/postModel'; import { Subject } from 'rxjs/Subject'; import { Observable } from 'rxjs/Observable&ap ...

The Viewchild element is currently nonexistent

(Angular 9) I'm having issues with using ViewChield() in my code. Here is a snippet of the HTML I am working with: <input type="text" pInputText [(ngModel)]="code" #inputStudent/> Here is what I have in my TypeScript file: ...

Tips for embedding an Angular application within another Angular application

I am working on two Angular projects at the moment. The first one is named App1, while the second one is called Angular Form Editor. My goal is to integrate the Form Editor into the App1 project. What steps should I take in order to achieve this integrat ...

Angular 2 chart showing horizontal stacking of databars

I am in search of a chart that visually represents different percentages. The purple bar should represent around 40%, the darkest blue approximately 10%, and the green about 8% of the total. After some research, I have come across this as a similar option, ...

The API request does not provide randomized results and does not show any display

I am facing an issue with a button that is supposed to fetch a random user from an API. When I retrieve all the users, the information is displayed correctly. However, when I try to select a user at random, it does not work as expected. Also, it seems to a ...

Is there a way to identify modifications in an Object and an Array when utilized as Input attributes in a sub-component?

After exploring the following two questions, I found that there weren't any helpful answers: Detect change in object of input array Detect changes in component input when it is a object In my current scenario, I am faced with the need to pass variou ...

The issue with making an HTTP POST request in Angular 2

Service: postJson() { var json = JSON.stringify({ "key": "CT", "values": ["FSP", "HMC", "PHYP","hell"] }); let headers = new Headers({'Content-Type':'application/json'}); //let options = new RequestOptions({ ...

Accessing the ViewModel property of a parent component from the ViewModel of its child in Aurelia

Having a scenario with two distinct components: <parent-component type="permanent"> <div child-component></div> </parent-component> class ParentComponentCustomElement { @bindable public type: string = "permanent"; } clas ...

Link a YAML file with interfaces in JavaScript

I'm currently learning JavaScript and need to convert a YAML file to an Interface in JavaScript. Here is an example of the YAML file: - provider_name: SEA-AD consortiumn_name: SEA-AD defaults: thumbnail Donors: - id: "https://portal.brain ...