Угловой /Javascript - верните правильный номер onKeyUp

Я пытаюсь проверить достоверность электронной почты (когда пользователь начинает вводить onkeyup), а затем, если письмо является действительным, я ввожу его в массив уникальных писем; однако я перестаю толкать массив, как только он достигнет определенного числа, в моем случае это 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 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 = /^(([^<>()\[\]\\.,;:\[email protected]"]+(\.[^<>()\[\]\\.,;:\[email protected]"]+)*)|(".+"))@((\[[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);
  }

Проблема:

Я считаю, что это неправильный способ сделать это, так как на каждой букве, напечатанной с клавиатуры, все работает снова и снова, перезаписывая переменные, работая для циклов и т.д....

Также возвращаемое значение для this.numberOfUsers неверно.

Ответы

Ответ 1

Если вы хотите применить проверку для разных записей, самым простым решением будет иметь один вход для каждого письма. Не уверен, что это подойдет вам, потому что вы не говорите, хотите ли вы придерживаться текстовой области или нет, но здесь моя идея:

Создайте форму, содержащую formArray со всеми необходимыми электронными письмами.

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

Здесь, как создать formArray:

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

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

  return emailsForms;
}

Здесь мы используем массив валидаторов и вызываем пользовательский emailValidator, который определяется следующим образом:

const emailRegex = /^(([^<>()\[\]\\.,;:\[email protected]"]+(\.[^<>()\[\]\\.,;:\[email protected]"]+)*)|(".+"))@((\[[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 } };
  };
}

Полный код компонента (TS):

@Component({
  selector: 'app-emails',
  templateUrl: './emails.component.html',
  styleUrls: ['./emails.component.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>

Здесь рабочая версия на Stackblitz:

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

Обратите внимание, что у вас есть доступ к собственности, valid для формы, чтобы вы знали, когда электронные письма X находятся в допустимом состоянии.

Ответ 2

Я понимаю, что у вас есть текстовое поле, где пользователь может вводить несколько адресов электронной почты. Вы хотите проверить их и добавить в массив.

Во-первых, вы не должны подписываться на ngModelChange, а не подписываться на событие blur. Это означает, что только когда пользователь выходит из поля, вы разбиваете входное значение на основе разделителя запятой и проверяете каждый.

Во-вторых, вы также можете отделить входное значение на основе /n, т.е. изменения строки. используя этот .split(/\r?\n/)

Таким образом, вам не нужно очищать массив, перебирать значение поля ввода каждый раз, когда пользователь что-то вводит.

Ответ 3

Если вы хотите, чтобы адрес электронной почты был полон до проверки, проверка на onBlur, как предложили другие, может быть вашим лучшим способом действий. Другим вариантом является продолжение прослушивания onKeyUp, но проверка запуска только в том случае, если ключ является конкретным ключом запуска.

Пример:

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

В этом примере 13 и 188 - это коды клавиш для ввода и запятой соответственно.

Ответ 4

У меня есть один вход и кнопка добавления. Возьмите ввод электронной почты и запустите логику события click кнопки add. Это обеспечит выполнение кода только при необходимости и предоставит пользователю лучший UX. Что-то вроде git сделано с профилями пользователей Справочный интерфейс