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

不羁岁月 提交于 2019-12-21 01:59:08

问题


What do I have to return in the customerNameValidator if the

async validation fails/succeeds that my 'customerName' FormControl is invalid?

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

回答1:


Rather than subscribing, you should map the observable to change the result of the returning stream, rather than reading from it.

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

Returning an object with a value that is true is how you should return the observable. You may be missing some important steps for async validators though, but because we don't gave all your code it's hard to say. Try checking out this article or this article for more information.




回答2:


I implemented an reactive form with an AsyncValidatorFn on angular 6.1.1. and would like to share some of my learning

I found out that angular does not (automatically) update the form control for AsyncValidatorFn as it does for internal sync validators .

so, as per the "AsyncValidatorFn" interface spec, you have to "manually" update your form control in your implementation of

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

and then, you will check the control state in the html element

What I had implemented is an Username existence checking that might be very commonly found in an user sign-up process

below are the code excerpts:

the form control

 // 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()]));

the custom async validator and the helper functions

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

note that I input the control as a parameter into the "mapErr" function, and set the control by "c.setErrors(err);".

the "return err;" statement return "ValidationErrors" as per the "AsyncValidatorFn" interface spec.

the "gabriel.filter()"queries the backend with the extracted username; and returns 0, -100, -1 respectively for "ok", "duplicated", and "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());
  }

the control checking in html file

 <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>

I also found out that the async validators are not trigger until sync validator are satisfied in one form control.

in my case, I also used the built-in Validators.pattern to define a minimum length of 3.(see above Username formControl definition)

the custom async validator never triggers as long as my input length is shorter than 3.



来源:https://stackoverflow.com/questions/42379203/what-to-return-in-the-angular-2-async-validator-when-using-observables

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!