Валидатор на доп и без очистки (ngx-chips, угловой) - PullRequest
0 голосов
/ 26 февраля 2019

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

Как я могу убедиться, что:

1) Валидатор срабатывает только при добавлении тега (т. Е. Пользователь нажимает ввод,пробел или запятая)

2) Если при вводе / пробел / запятая электронная почта недействительна, это значение сохраняется (т. е. оно не очищается ..., чтобы пользователь мог его исправить)

Стеки-блиц здесь: https://stackblitz.com/edit/ngx-chips-example-2qdudc

Ниже мой валидатор электронной почты:

public validators = [ this.must_be_email ];
  public errorMessages = {
      'must_be_email': 'Please be sure to use a valid email format'
  };
  private must_be_email(control: FormControl) {        
      var EMAIL_REGEXP = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,3}$/i;
      if (control.value.length != "" && !EMAIL_REGEXP.test(control.value)) {
          return { "must_be_email": true };
      }
      return null;
  }

Ниже приведен тег:

<tag-input [(ngModel)]='emails' 
name="emails" 
#email="ngModel" 
[errorMessages]="errorMessages"
[validators]="validators" 
[editable]='true' 
(onTagEdited)="onTagEdited($event)" 
[separatorKeyCodes]="[32,188,186,13,9]"
[placeholder]="'Add email'" 
[secondaryPlaceholder]="'Enter email address(es)'" 
[clearOnBlur]="true" 
[addOnPaste]="true"
[addOnBlur]="true"
[pasteSplitPattern]="splitPattern" 
theme='bootstrap' 
required >
</tag-input>

Для 2), Я попытался изменить "return null" на control.value в валидаторе ... но это не сработало

Ответы [ 2 ]

0 голосов
/ 07 марта 2019

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

Как и в случае ответа @ AlesD, я выбрал решение, использующее onAdding.Одна проблема, которую он поднимает, это проблема использования this.Чтобы обойти эту проблему, я использую функцию bind(), когда это необходимо.

Чтобы реализовать желаемое поведение, я сделал три вещи:

  1. Изменил функцию валидатора так, чтобы она возвращала ошибку только в том случае, если поле addFirstAttemptFailed былоправда.Это предотвратит выполнение валидатора.
  2. Добавьте обратный вызов к onAdding.Он проверяет тег и, если проверка завершается неудачно, устанавливает addFirstAttemptFailed в значение true и возвращает наблюдаемую ошибку (я обновил до rxjs 6).Возникновение этой ошибки препятствует добавлению тега.
  3. После успешного добавления элемента addFirstAttemptFailed возвращается в значение false, чтобы поведение могло снова начаться для следующего тега.

К сожалению, метод, который вызывается во время onAdding, имеет несколько буровых установок.

  • Чтобы получить подтверждение, мне нужно было получить ссылку на TagInputComponent чипа и вызвать setInputValue(), передаваязначение, которое уже установлено.Поверьте мне, я попробовал тысячу вариантов, прежде чем наткнулся на этот побочный эффект.Попытка вызвать updateValueAndValidty() либо для экземпляра FormControl в вашем компоненте, либо для различных экземпляров Form и FormControl в TagInputComponent никогда не работала.
  • Чтобы предотвратить добавление (и не очистить ввод), ядолжен возвращать ошибку, наблюдаемую от throwError().К сожалению, внутренняя настройка подписки заключается в том, что компонент TagInput вызывает только catchError() в своей функции обратного вызова подписки, а не в наблюдаемом источнике.Таким образом, ошибка отображается в консоли.Опять же - я попробовал несколько способов обойти это.

Соответствующий код

@ViewChild('tagInput')
tagInput: SourceTagInput;


public validators = [ this.must_be_email.bind(this) ];
public errorMessages = {
  'must_be_email': 'Please be sure to use a valid email format'
};

public readonly onAddedFunc = this.beforeAdd.bind(this);

private addFirstAttemptFailed = false;

private must_be_email(control: FormControl) {        
  if (this.addFirstAttemptFailed && !this.validateEmail(control.value)) {
    return { "must_be_email": true };
  }
  return null;
}

private beforeAdd(tag: string) {

  if (!this.validateEmail(tag)) {
    if (!this.addFirstAttemptFailed) {
      this.addFirstAttemptFailed = true;
      this.tagInput.setInputValue(tag);
    }
    return throwError(this.errorMessages['must_be_email']);
  }
  this.addFirstAttemptFailed = false;
  return of(tag);
}
0 голосов
/ 04 марта 2019

У ngx-chips есть событие onAdding , которое вы можете использовать для дополнительной проверки.Внутри обработчика событий вы можете проверить, является ли компонент действительным, и отменить добавление, если элемент управления недействителен.Тогда текст останется.Для клавиши Enter это не может работать, потому что клавиша Enter закодирована для отправки формы и всегда очищает текст.Это можно увидеть в исходном коде GitHub компонента tag-input-form , который используется внутри тег-ввода.Проверьте метод onKeyDown.

Вот пример реализации обработчика onAdding в вашем компоненте:

public onAdding(tag): Observable<string> {
  if (!this.hasErrors()) { // this is tricky the this here is actually the ngx-chips tag-input component
    return of(tag);
  } else {
    return EMPTY;
  }
}

Как я уже упоминал в комментарии в коде из-за того, как происходит событиеОбработчик называется this, внутри функции на самом деле является компонент ввода тегов ngx-chips, а не ваш компонент, который вы обычно ожидаете.

После того, как у вас есть этот метод, вы просто привязываете его в шаблоне, и он должен работать.

<tag-input ... [onAdding]="onAdding">

Я также создал форк вашего стекаблица с этой реализацией.

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

...