使用 observables 时 angular 2 异步验证器中的 return

What to return in the angular 2 async validator when using observables

如果

我必须 return 在 customerNameValidator 中做什么

异步验证 fails/succeeds 我的 '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");
        }
   });
}

您应该映射可观察对象以更改 returning 流的结果,而不是从中读取,而不是订阅。

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

返回值为 true 的对象是您应该 return observable 的方式。虽然您可能错过了异步验证器的一些重要步骤,但因为我们没有提供您的所有代码,所以很难说。 Try checking out this article or this article 获取更多信息。

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

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

因此,根据 "AsyncValidatorFn" 界面规范,您必须 "manually" 在

的实现中更新表单控件
(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);"设置控件。

"return err;" 声明 return "ValidationErrors" 根据 "AsyncValidatorFn" 接口规范。

"gabriel.filter()"使用提取的用户名查询后端;和 returns 0、-100、-1 分别对应 "ok"、"duplicated" 和 "operation failed"

  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,自定义异步验证器就不会触发。