【问题标题】:Validator on add and without clearing (ngx-chips, angular)添加和不清除的验证器(ngx-chips,角度)
【发布时间】:2019-02-26 02:00:58
【问题描述】:

我正在使用 ngx-chips 将电子邮件列表作为标签添加到输入中。验证器确保每个标签看起来像一封电子邮件。

我如何确保:

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

2)如果在输入/空格/逗号时邮件无效,则该值仍然存在(即,它不清除......以便用户可以修复它)

stackblitz 在这里: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...但这不起作用

【问题讨论】:

  • 您是否要在用户点击回车之前删除错误警告?
  • 是的。试图在用户点击输入之前从显示中删除警告。现在,它会在他们输入时显示,这会分散用户的注意力
  • 您是否尝试过为此使用“asyncValidators”?
  • 从您添加的示例中,“问题”来自您使用的模块。您可以根据自己的需要编辑模块。但从快速查看它的模块方面而不是您可以轻松更改的东西

标签: angular validation tags angular7 ngx-chips


【解决方案1】:

这个控件的笨拙实现最终使事情变得困难。如果它是一个具有包含当前输入和标签数组的模型的 ControlValueAccessor,那么找到解决方案会简单得多。

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

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

  1. 修改验证器函数,使其仅在字段 addFirstAttemptFailed 为真时返回错误。这将阻止验证器执行。
  2. 向onAdding 添加回调。它验证标签,如果验证失败,将 addFirstAttemptFailed 设置为 true 并返回可观察到的错误(我升级到 rxjs 6)。抛出此错误会阻止添加标签。
  3. 成功添加项目后,将 addFirstAttemptFailed 设置回 false,以便下一个标签的行为可以再次开始。

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

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

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

【讨论】:

  • 谢谢丹尼尔。那行得通。作为一个仅供参考,这似乎会破坏粘贴(即,粘贴时分隔符代码不再起作用),但它解决了清除/验证器的问题。
  • 很好的发现,但看起来这不适用于较新版本的库:(您对如何解决该问题有任何建议吗?这里的问题仍然开放@ 987654322@
【解决方案2】:

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。

如果这对您不起作用,您可能需要联系组件的作者以获取更多详细信息或使用其他组件。例如,Angular 材质组件包含类似的chip input component。

【讨论】:

  • 谢谢。但是,正如您所指出的,它仍然清除了价值。我也处理过这个问题,但无法让它工作。
  • 它只会在按 Enter 键清除所有其他有效键的值。我现在更仔细地查看了 GitHub 中的代码,当您按 Enter 时,它在控件中进行了硬编码,它认为您正在提交表单并清除文本。也会将此添加到答案中。
  • 谢谢!验证器有什么办法只显示 onAdding 吗?
  • 不,不幸的是,您无法根据我所看到的更改验证行为。它使用默认值,每次值更改都会更新。
  • AlesD,感谢您的帮助。我把 50 分给了丹尼尔,因为他的解决方案涵盖了这两个问题。不过,我非常感谢您为帮助找到答案所做的工作。
猜你喜欢
  • 2020-06-28
  • 2020-09-02
  • 2018-11-09
  • 2013-09-10
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
  • 2019-09-23
  • 1970-01-01
相关资源
最近更新 更多