admin管理员组

文章数量:1294329

I am trying to check the email validity (when the user start typing onkeyup), then if the email is valid I push it into an array of unique emails; however, I stop pushing to the array once it reaches a certain number, in my case it's 3.

     <textarea (ngModelChange)="onKeyUp($event)"></textarea>

     onKeyUp(ev) {

      let finalEmailList = []
      this.finalEmailList = [];

      this.numberOfUsers = 3;

      let emails = ev.replace(' ', '').split(/,| /);

      emails.forEach(email => {
        if (this.validateEmail(email)) {
          //If the email has a valid format, the push it to the array
          finalEmailList.push(email);
          //it's a lodash function to clean the array an keep only unique emails in the array
          this.finalEmailList = _.uniq(finalEmailList);

           if (this.finalEmailList.length <= this.numberOfUsers) {
          this.numberOfUsers -= this.finalEmailList.length;
          }
        }
      })
    }

  //returns true if the email has a valid format
  validateEmail(email) {
    var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
  }

The issue:

I believe it's a wrong way to do it as on each and every letter printed from the keyboard everything runs again and again, resetting variables, running for loops, etc...

Also the value returned for this.numberOfUsers is not correct.

I am trying to check the email validity (when the user start typing onkeyup), then if the email is valid I push it into an array of unique emails; however, I stop pushing to the array once it reaches a certain number, in my case it's 3.

     <textarea (ngModelChange)="onKeyUp($event)"></textarea>

     onKeyUp(ev) {

      let finalEmailList = []
      this.finalEmailList = [];

      this.numberOfUsers = 3;

      let emails = ev.replace(' ', '').split(/,| /);

      emails.forEach(email => {
        if (this.validateEmail(email)) {
          //If the email has a valid format, the push it to the array
          finalEmailList.push(email);
          //it's a lodash function to clean the array an keep only unique emails in the array
          this.finalEmailList = _.uniq(finalEmailList);

           if (this.finalEmailList.length <= this.numberOfUsers) {
          this.numberOfUsers -= this.finalEmailList.length;
          }
        }
      })
    }

  //returns true if the email has a valid format
  validateEmail(email) {
    var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
  }

The issue:

I believe it's a wrong way to do it as on each and every letter printed from the keyboard everything runs again and again, resetting variables, running for loops, etc...

Also the value returned for this.numberOfUsers is not correct.

Share edited May 19, 2018 at 14:12 Folky.H asked May 16, 2018 at 23:02 Folky.HFolky.H 1,2044 gold badges16 silver badges40 bronze badges 5
  • let emails = ev.replace(' ', '').split(/,| /); you call .replace on the $event – Karen Grigoryan Commented May 19, 2018 at 14:23
  • Create a custom ponent, subscribe on blur, validate email only once and emit the event to the subscriber. or Use pattern html5 attribute – Drag13 Commented May 19, 2018 at 14:24
  • let email = ev.value.replace(' ', '').split(/,| /); – Ritwick Dey Commented May 19, 2018 at 15:10
  • Your code runs every time someone releases a key, si youll want to find a way go gather the keys and run the loop once the user is done. Regarding the number od users issue, I dont know what you are trying to achieve there, do you want to equalize the amount of users and emails in list? – Jusmpty Commented May 20, 2018 at 8:05
  • You should use a directive which will simply deny the wrong input, so you will get always correct email in Input. however user can copy and paste the wrong email. That you can check against the regex. The same regex you can use in your directive. – Deepender Sharma Commented Dec 30, 2019 at 12:38
Add a ment  | 

4 Answers 4

Reset to default 1

If you want the email address to be plete before validating, validating onBlur as others have suggested may be your best course of action. Another option is to continue listening for onKeyUp, but only trigger validation if the key is a specific trigger key.

Example:

onKeyUp(event) {
  if ([13, 188].includes(event.keyCode)) {
    validateEmails()
  }
}

In this example, 13 and 188 are the key codes for Enter and ma, respectively.

If you want to apply a check on different entries, the simplest solution would be to have one input per email. Not sure it'll fit your need as you haven't say whether you want to stick with a textarea or not but here's my idea:

Create a form containing a formArray with all the required emails.

this.emailsForm = this.fb.group({
  emails: this.fb.array(this.getEmailsFormGroup())
});

Here's how to create the formArray:

getEmailsFormGroup() {
  const emailsForms: FormGroup[] = [];

  for (let i=0; i<this.nbEmails; i++) {
    emailsForms.push(this.fb.group({
      email: ['', [emailValidator()], []]
    }));
  }

  return emailsForms;
}

Here we're taking advantage of the validators array and calling a custom validator emailValidator, which is defined like that:

const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

export function emailValidator(): ValidatorFn {
  return (control: AbstractControl): { [key: string]: any } => {
    return emailRegex.test(control.value) ?
      null :
      { 'not-email-like': { value: control.value } };
  };
}

Full ponent code (TS):

@Component({
  selector: 'app-emails',
  templateUrl: './emails.ponent.html',
  styleUrls: ['./emails.ponent.css']
})
export class EmailsComponent implements OnInit {
  nbEmails = 3;

  emailsForm: FormGroup;

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.emailsForm = this.fb.group({
      emails: this.fb.array(this.getEmailsFormGroup())
    });
  }

  getEmailsFormGroup() {
    const emailsForms: FormGroup[] = [];

    for (let i = 0; i < this.nbEmails; i++) {
      emailsForms.push(this.fb.group({
        email: ['email-' + i, [emailValidator()], []]
      }));
    }

    return emailsForms;
  }
}

HTML:

Please enter the {{ nbEmails }} required email{{ nbEmails > 1 ? 's' : '' }}

<form [formGroup]="emailsForm">
  <div formArrayName="emails">
    <div *ngFor="let email of emailsForm.controls['emails'].controls; let i=index" [formGroupName]="i">
      <input
        type="text"
        formControlName="email"
      >
    </div>
  </div>
</form>

<hr>

<div>
  VALID? {{ emailsForm.valid }}
</div>

<hr>

<div>
  <pre>
    {{ emailsForm.value | json }}
  </pre>
</div>

Here's a working version on Stackblitz:

https://stackblitz./edit/angular-lxltri?file=src%2Fapp%2Femails%2Femails.ponent.ts

Notice that you have access to the property valid of the form so you know when the X emails are in a valid state.

What I understand is, you have a textarea, where user can enter multiple emailIds. You want to validate each and add into an array.

First, you should not subscribe to ngModelChange, instead subscribe to blur event. Which means only when user moves out of the field, you split the input value based on ma separator and validate each.

Second, you can also separate the input value based on /n i.e. line change. using this .split(/\r?\n/)

This way you don't have to clean array, loop through input field value every time user enters something.

I rather have a single input and a add button. Take the email input and run the logic on click event of add button.That will make sure code runs only when needed and provides user with a better UX. Something like git has done with user profiles Reference UI

本文标签: AngularJavascriptreturn the correct number onKeyUpStack Overflow