【问题标题】:What to return in the angular 2 async validator when using observables使用 observables 时在 Angular 2 异步验证器中返回什么
【发布时间】:2018-10-16 21:13:06
【问题描述】:

如果

我的 'customerName' FormControl 无效的异步验证失败/成功?

this.customerForm = this.formBuilder.group({
customerName: 
[this.newCustomerName, [Validators.minLength(2), Validators.required],[this.customerNameValidator.bind(this)]]
});


customerNameValidator(c: AbstractControl)
{
   return this.service.customerExists(c.value,this.companyId).subscribe(response =>
   {
        if(response == true)
        {
             alert("true");
        }
        else
        {
            alert("false");
        }
   });
}

【问题讨论】:

  • 一个 observable 发出与验证器返回的内容相同的内容:如果没有错误,则返回 null,如果有错误,则返回带有错误键的对象。

标签: angular angular2-forms angular2-observables


【解决方案1】:

您应该映射 observable 以更改返回流的结果,而不是订阅,而不是从中读取。

customerNameValidator(c: AbstractControl)
{
   return this.service.customerExists(c.value,this.companyId).map(response =>
   {
        if(response == true)
        {
            return { customerExists: true };
        }
        else
        {
            return;
        }
   });
}

返回一个值为 true 的对象是你应该返回 observable 的方式。不过,您可能遗漏了异步验证器的一些重要步骤,但由于我们没有提供您所有的代码,所以很难说。 Try checking out this articlethis article 了解更多信息。

【讨论】:

  • 只是想知道如何为 FormBuilder 中的异步验证实现新的自定义验证器类?谢谢
  • @HungBui 与任何其他自定义验证器类的实现方式相同。您的验证器应该只是一个传递到表单控件的函数。 blog.thoughtram.io/angular/2016/03/14/…
  • 谢谢@Adam - 我正在查看您提供的第一个链接,自定义验证器是作为验证器类的扩展类创建的。但是,Validators.composeAsync() 方法需要一个 AsyncValidatorFn 类对象。只是想知道是否可以将 AsyncValidator 转换为 AsyncValidatorFn 以便可以注入?希望这是有道理的。
  • 你不会将整个类传递给你的验证器,只是特定的函数。如果您的Validator 类具有异步函数usernameAlreadyUsedanotherAsyncFunction,那么您可以将其传递给验证器。查看interface for AsyncValidatorFn,您只需传入一个控件,验证器会自动执行此操作。
  • @Adam - 我无法在此处添加我的示例代码,所以您能否看一下单独的答案,并说明如何将其传递给验证器。
【解决方案2】:

我在 Angular 6.1.1 上使用 AsyncValidatorFn 实现了一个反应式表单。并想分享我的一些学习经验

我发现 angular 不会(自动)更新 AsyncValidatorFn 的表单控件,就像它对内部同步验证器所做的那样。

因此,根据“AsyncValidatorFn”接口规范,您必须在实现中“手动”更新表单控件

(c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null>;

然后,您将检查 html 元素中的控件状态

我实施的是用户名存在检查,这可能在用户注册过程中很常见

以下是代码摘录:

表单控件

 // Supports alphabets and numbers no special characters except underscore('_') and dash('-') min 3 and max 20 characters.
    this.userName = new FormControl('', Validators.compose([Validators.required, Validators.pattern('^[A-Za-z0-9_-]{3,20}$')]),Validators.composeAsync([this.checkUser()]));

自定义异步验证器和辅助函数

checkUser (): AsyncValidatorFn{

    return (c: AbstractControl): Observable<ValidationErrors> => {
      return c
        .valueChanges
        .debounceTime(400)
        .mergeMap(value => this.gabriel.filter({'userName':value}))
        .map(stat => this.mapErr(c, stat));
    } 

  }

  private mapErr(c: AbstractControl, res: any): ValidationErrors{
    let err: ValidationErrors;
    switch (res['state']){
      case  0:
        err = null;
        break;
      case -100:
        err = {'existed': true};
        break; 
      case -1:
      default:
        err = {'failed': true};                      
    }
    c.setErrors(err);
    return err;
  }

请注意,我将控件作为参数输入到“mapErr”函数中,并通过“c.setErrors(err);”设置控件。

"返回错误;"语句根据“AsyncValidatorFn”接口规范返回“ValidationErrors”。

“gabriel.filter()”用提取的用户名查询后端; “ok”、“duplicated”、“operation failed”分别返回0、-100、-1

  filter(json): Observable<{}>{
    let body = JSON.stringify(json);
    let headers = new Headers({'Content-Type': 'application/json'});
    let options = new RequestOptions({ headers: headers });
    return this.http.post(Cons.filter, body, options).timeout(10000).map((res:Response) => res.json());
  }

html文件中的控件检查

 <form [formGroup]="sf" (ngSubmit)="signin()">
          <ion-item>
            <ion-label>UserName</ion-label>
            <ion-input type="text" formControlName="userName" [class.invalid]="userName.dirty&&userName.invalid&&userName.errors!=null" ></ion-input>
          </ion-item>
            <p *ngIf="userName.dirty && userName.hasError('existed')">
              Username already existed
            </p>
            <p *ngIf="userName.dirty && userName.hasError('failed')">
              can not check validity of Username 
            </p>

我还发现异步验证器不会触发,直到同步验证器在一个表单控件中得到满足。

在我的例子中,我还使用内置的 Validators.pattern 来定义最小长度为 3。(参见上面的用户名 formControl 定义)

只要我的输入长度小于 3,自定义异步验证器就永远不会触发。

【讨论】:

    猜你喜欢
    • 2019-03-12
    • 2017-03-02
    • 2019-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 1970-01-01
    相关资源
    最近更新 更多