添加时不清除的验证器(ngx芯片,角度)

时间:2019-02-26 02:00:59

标签: angular validation tags angular7 ngx-chips

我正在使用ngx-chips将电子邮件列表作为标签添加到输入中。验证程序确保每个标签都像电子邮件一样。

我如何确保:

1)验证器仅在添加标签时触发(即用户点击回车,空格或逗号)

2)如果在按Enter /空格/逗号时电子邮件无效,则该值仍然存在(即,它不会清除...以便用户可以对其进行修复)

这里有个堆叠闪电战: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 :(得分:2)

最终,此控件的笨拙实现使事情变得困难。如果它是一个ControlValueAccessor,并且其模型包含当前输入和标记数组,那么找到解决方案将容易得多。

与@AlesD的答案一样,我提供了一个利用onAdding的解决方案。他提出的一个问题是使用this的问题。为了解决这个问题,我在必要时使用了bind()函数。

为了实现您想要的行为,我做了三件事:

  1. 修改验证器函数,以便仅在字段 addFirstAttemptFailed 为true时才返回错误。这将阻止验证程序执行。
  2. onAdding添加回调。它验证标签,如果验证失败,则将 addFirstAttemptFailed 设置为true并返回可观察到的错误(我已升级到rxjs 6)。引发此错误会阻止添加标签。
  3. 成功添加项目后, addFirstAttemptFailed 会重新设置为false,这样行为就可以从下一个标记重新开始。

不幸的是,在onAdding期间调用的方法有一些绑定。

  • 为了进行验证,我必须获取对芯片的TagInputComponent的引用并调用setInputValue(),并传递已设置的值。相信我,在偶然发现这种副作用之前,我尝试了上千种变体。尝试在组件上的FormControl实例或TagInputComponent中的Form和FormControl的各种实例上调用updateValueAndValidty()都是行不通的。
  • 为了防止添加(并且不清除输入),我必须返回可从throwError()观察到的错误。不幸的是,内部设置订阅的方式是TagInput组件仅在其订阅回调函数上调用catchError(),而不在可观察的源上调用。因此错误将显示在控制台中。再次-我尝试了多种解决方法。

Relevant code

@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);
}

答案 1 :(得分:1)

ngx-chips有一个事件onAdding,您可以用来进行其他检查。在事件处理程序内,您可以检查组件是否有效,如果控件无效,则可以取消添加。然后文本将保留。对于Enter键,它无法工作,因为Enter键已编码为提交表单,并且始终清除文本。您可以在标签输入内部​​使用的GitHub source code of the tag-input-form component中看到它。检查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">

我还通过此实现创建了fork of your stackblitz

如果这不适用于您,则可能需要联系组件的作者以获取更多详细信息或使用其他组件。例如,角材料成分包含一个类似的chip input component