Chunbin Li
Chunbin Li

Reputation: 2244

How can I get Validators from the formControl directly?

enter image description here

enter image description here

enter image description here

I have an email field, and I added two validators(required, email), I want to check validation status on the input event to call API check dose a member of my system when it's valid, if it's invalid don't to call API and don't show error message on the page.

I will show error message on blur event(focusOut email's input),firstly I used formControl.validator(formControl) to trigger validators and check formControl.valid,I got valid status successful but it will show error message on the page because I subscribed statsuChange to show an error message when status equal to invalid.

currently, I save validators in a variable and pass to initEmailChaingeEvent() to check validation status without statusChange event. It's can work, but I think it's not a good way, here's an example of my implementation:

live example

export class AppComponent {
  public sampleForm: FormGroup;

  @ViewChild('emailElm')
  emailElm: ElementRef;

  ngOnInit() {
    this.initForm();
  }

  initForm() {
    const emailValidtors = [
      Validators.required,
      Validators.email
    ]

    const emailFC = new FormControl(null, {
      validators: emailValidtors,
      updateOn: 'blur'
    });
    //
    this.sampleForm = new FormGroup({
      'email': emailFC
    });
    //
    this.initEmailChaingeEvent({
      emailFC: emailFC,
      validtors: emailValidtors
    });
    //
    this.sampleForm.valueChanges.subscribe((val) => {
      console.log('_blue event:valueChanges', val)
    });
    //
    this.initShowErrorMsgEvent({
      fc: emailFC
    });
  }

  private initEmailChaingeEvent(arg: {
    emailFC: FormControl,
    validtors: any[]
  }) {
    fromEvent(this.emailElm.nativeElement, 'input')
      .pipe(debounceTime(500))
      .subscribe((event: Event) => {
        const currentEmail = (event.target as HTMLInputElement).value;
        // check is valid
        // **quention** : how can I get validtors from fromcontrol self 
        // if I use  arg.emailFC.validator(arg.emailFC) to ehcek status , it will trigger oberservable in initShowErrorMsgEvent(),
        //  but I just want to got valid result , I don't want to show error msg on UI at this time

        for (const validator of arg.validtors) {
          const inValid = validator(arg.emailFC);
          if (inValid) {
            console.log('input event:invalid', currentEmail);
            return;
          }
        }
        // **do sometheng when all valid**
        console.log('input event:call API , email:',currentEmail );
      });
  }

  private initShowErrorMsgEvent(arg: {
    fc: FormControl,
  }) {
    arg.fc.statusChanges
      .subscribe((status) => {
        // console.log('status' , status);
        if (status === 'INVALID') {
          // show error msg....
          console.log('_show error msg by antoher component');
        }
      });
  }
}
<form [formGroup]="sampleForm">
  <input formControlName="email" #emailElm >
</form>

Upvotes: 9

Views: 6682

Answers (3)

Chunbin Li
Chunbin Li

Reputation: 2244

thanks everyone give me more idea,I fixed it through formControl's validator property,it's my modifyed list:

  • only pass value to validators avoid trigger statusChange emitter

live example

private initEmailChaingeEvent(arg:{
   emailFC : FormControl,
   ....
}) {
  ...
  const inValid = arg.emailFC.validator({
      value: currentEmail
    }
    as any);
  ....
}

Upvotes: 0

Zsolt Tolvaly
Zsolt Tolvaly

Reputation: 3616

You over-complicated the task. First, declare your form, and control validators. If you compose a validator from a list of validators, they will be checked in order of definition. So, first the required, then "if it's valid email", and last you custom validator will check if it's unique

 ....
 this.emailForm = this.fb.group({
       emailAddress: [null, Validators.compose([Validators.required, Validators.email, uniqueEmailValidator()])]
 });
 ...

Then you create your custom validator for checking the user email by the API. More info on custom validators: Angular docs

function uniqueEmailValidator(){
    ...
}

Upvotes: 2

hugmungus
hugmungus

Reputation: 896

There's a lot going on here that needs some work. First off, I'd subscribe to the formValue changes of the control instead of using an Observable on the native element.

this.sampleForm.get('email').valueChanges.subscribe((event) => {
    // CODE IN HERE
}

ValueChanges is a property on the formControl that emits an event when the value changes. https://angular.io/api/forms/AbstractControl

Next, to access the validators, you can simply check the form control if it is valid.

this.sampleForm.get('email').valid();

If any validator is invalid, this will be false, if all validators are valid, it will be true.

EDIT:

From your comment, sounds like you want a debounceTime pipe in there:

this.sampleForm.get('email').valueChanges
.pipe(debounceTime(500), distinctUntilChanged())
.subscribe((event) => {
    if (this.sampleForm.get('email').valid) {
         // Your API logic here
    }
}

DebounceTime basically delays the event from being processed and will throw out any pending events in the queue.

debounceTime delays values emitted by the source Observable, but drops previous pending delayed emissions if a new value arrives on the source Observable. http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-debounceTime

Upvotes: 0

Related Questions