admin管理员组

文章数量:1302958

Here is the demo plnkr. I am trying to implement a custom async validator for a OTP input which has a text box and a verify button. I want to validate the input only when the user clicks on the verify OTP button or form submit button. Currently validation is happening on the text change event and it's not working. Form HTML:

<form [formGroup]="registrationForm" (ngSubmit)="registrationForm.valid && submitRegistration(registrationForm.value)" novalidate>
  <fieldset class="form-group">
    <label for="e-mail">Mobile</label>
    <div class="input-group">
      <input type="text" class="form-control" placeholder="Mobile" formControlName="mobile">
      <span class="input-group-btn">
        <button class="btn btn-secondary" type="button">Send OTP</button>
      </span>
    </div>
    <div class="form-text error" *ngIf="registrationForm.controls.mobile.touched">
      <div *ngIf="registrationForm.controls.mobile.hasError('required')">Mobile is required.</div>
    </div>
  </fieldset>
  <fieldset class="form-group">
    <label for="e-mail">Verify OTP</label>
    <div class="input-group">
      <input type="text" class="form-control" placeholder="OTP" formControlName="otp">
      <span class="input-group-btn">
        <button class="btn btn-secondary" (click)="veryOTPAsyn(otp)" type="button">Verify</button>
      </span>
    </div>
    <div class="form-text error" *ngIf="registrationForm.controls.otp.touched">
      <div *ngIf="registrationForm.controls.otp.hasError('required')">OTP is required.</div>
      <div *ngIf="registrationForm.controls.otp.hasError('invalidOtp')">OTP is invalid.</div>
    </div>
  </fieldset>
  <button class='btn btn-primary' type='submit' [disabled]='!registrationForm.valid'>Submit Registration Form</button>
</form>

Form Component:

export class ExampleFormComponent {
  registrationForm: FormGroup;

  constructor(public fb: FormBuilder) {
    // Example use of FormBuilder, FormGroups, and FormControls
    this.registrationForm = fb.group({
      mobile: ['', Validators.required],
      otp: ['', Validatorspose([Validators.required, this.veryOTPAsyn.bind(this)])],
      dob: ['', Validators.required],
      email: ['', Validatorspose([Validators.required,  emailValidator])],
      password: ['', Validators.required],
      confirmPassword: ['', Validators.required],
      firstName: ['', Validators.required],
      lastName: ['', Validators.required]
    }, {validator: matchingPasswords('password', 'confirmPassword')})

  }

  submitRegistration(value: Object): void {
    console.log(value);
  }

  veryOTPAsyn(otpControl: FormControl): Promise<any> {
    console.log(otpControl)
    console.log(otpControl.hasError('invalidOtp'))
    return new Promise<any>(
      (resolve, reject) => {
        setTimeout(() => {
          resolve({invalidOtp:true});
        }, 500);
      });
  }

}

Here is the demo plnkr. I am trying to implement a custom async validator for a OTP input which has a text box and a verify button. I want to validate the input only when the user clicks on the verify OTP button or form submit button. Currently validation is happening on the text change event and it's not working. Form HTML:

<form [formGroup]="registrationForm" (ngSubmit)="registrationForm.valid && submitRegistration(registrationForm.value)" novalidate>
  <fieldset class="form-group">
    <label for="e-mail">Mobile</label>
    <div class="input-group">
      <input type="text" class="form-control" placeholder="Mobile" formControlName="mobile">
      <span class="input-group-btn">
        <button class="btn btn-secondary" type="button">Send OTP</button>
      </span>
    </div>
    <div class="form-text error" *ngIf="registrationForm.controls.mobile.touched">
      <div *ngIf="registrationForm.controls.mobile.hasError('required')">Mobile is required.</div>
    </div>
  </fieldset>
  <fieldset class="form-group">
    <label for="e-mail">Verify OTP</label>
    <div class="input-group">
      <input type="text" class="form-control" placeholder="OTP" formControlName="otp">
      <span class="input-group-btn">
        <button class="btn btn-secondary" (click)="veryOTPAsyn(otp)" type="button">Verify</button>
      </span>
    </div>
    <div class="form-text error" *ngIf="registrationForm.controls.otp.touched">
      <div *ngIf="registrationForm.controls.otp.hasError('required')">OTP is required.</div>
      <div *ngIf="registrationForm.controls.otp.hasError('invalidOtp')">OTP is invalid.</div>
    </div>
  </fieldset>
  <button class='btn btn-primary' type='submit' [disabled]='!registrationForm.valid'>Submit Registration Form</button>
</form>

Form Component:

export class ExampleFormComponent {
  registrationForm: FormGroup;

  constructor(public fb: FormBuilder) {
    // Example use of FormBuilder, FormGroups, and FormControls
    this.registrationForm = fb.group({
      mobile: ['', Validators.required],
      otp: ['', Validators.pose([Validators.required, this.veryOTPAsyn.bind(this)])],
      dob: ['', Validators.required],
      email: ['', Validators.pose([Validators.required,  emailValidator])],
      password: ['', Validators.required],
      confirmPassword: ['', Validators.required],
      firstName: ['', Validators.required],
      lastName: ['', Validators.required]
    }, {validator: matchingPasswords('password', 'confirmPassword')})

  }

  submitRegistration(value: Object): void {
    console.log(value);
  }

  veryOTPAsyn(otpControl: FormControl): Promise<any> {
    console.log(otpControl)
    console.log(otpControl.hasError('invalidOtp'))
    return new Promise<any>(
      (resolve, reject) => {
        setTimeout(() => {
          resolve({invalidOtp:true});
        }, 500);
      });
  }

}
Share Improve this question edited Jul 15, 2019 at 6:47 Kamil Naja 6,6926 gold badges37 silver badges52 bronze badges asked Jun 27, 2017 at 16:00 Saurabh PalatkarSaurabh Palatkar 3,38412 gold badges52 silver badges112 bronze badges 0
Add a ment  | 

2 Answers 2

Reset to default 5

Try this :

 otp: ['', Validators.required, this.veryOTPAsyn.bind(this)]

Async validators go in 3rd argument

I would consider to remove the custom validation and instead set / remove error when user clicks on button instead, since the custom validators will run when ponent is initialized, as well as whenever input value changes. So have your click event, and do something like this (pseudo code):

(click)="veryOTPAsyn(registrationForm.controls.otp)"

and TS:

veryOTPAsyn(ctrl: FormControl) {
  if(ctrl.value == 'hey') {
    ctrl.setErrors({'invalidOtp':true})
  } else {
    ctrl.setErrors({'invalidOtp':null})
  }
}

Forked PLUNKER.


EDIT:

But if you want to go the route of using the async validator, just add the validator as third argument, but then you don't need the 'validate' button.

otp: ['', [Validators.required], [this.veryOTPAsyn]]

or do it like it's done now after the release of v 5.0.0

otp: ['', {validators: [Validators.required], asyncValidators: [this.veryOTPAsyn]}]

PLUNKER (pre v.5.0.0, so the first option of marking async validator is used)

本文标签: javascriptAngular custom async validator not workingStack Overflow