0

I am playing with Angular form validation to implement a custom async validator which works well with Promises, but.. I would like to avoid Promises and use Observable to benefit from its useful methods and make it simpler.

I have done the following thing which is working well:

class OrderFormComponent{

    issueSubject: FormControl;

    static checkAsyncValue(val: string){
        return new Observable(observer => {
              setTimeout(() => { //Timeout just to simulate an async call
                  if( val.substr(0,2) != "#SUBJECT_" ) {
                    observer.next(false);
                  } else {
                    observer.next(true);
                  }
                  observer.complete();
              }, 500);
        });
    }


    constructor(fb: FormBuilder){

        this.issueSubject = fb.control('', [Validators.required], []]);
        const issueSubject = this.issueSubject;
        let checkValue = function(value){
            OrderFormComponent.checkAsyncValue(value).subscribe((result) => {
                  if (result !== true) {
                    issueSubject.setErrors({
                      notunique: true
                    });
                  }
            });
        }
        issueSubject.valueChanges.debounceTime(500).distinctUntilChanged().subscribe(value => {
            checkValue(value);
        });
        this.issueSubject.setValue('Test Bad Subject');

        this.issueForm = fb.group({
            subject:   this.issueSubject
        });     
    }

}   

But, what I would like to do is to not be based on "valueChanges" and simplify things by adding a custom validator directly in the async validators array of the FormControl as explained below:

this.issueSubject = fb.control('', [Validators.required], [
    //Adding here something like OrderFormComponent.checkAsyncValue
]]);

Please note I would like to keep the usage of the following:

debounceTime(500).distinctUntilChanged()

Is there a way to do it or is there mandatory to be based on valueChanges Observable?

EDIT: Something to add, one important drawback with my example is that the 'pending' property of the form won't be set while doing the custom asynchronous validation

Thank you in advance

Bil5
  • 502
  • 1
  • 5
  • 15
  • You might find this issue useful/interesting: https://github.com/angular/angular/issues/9119 – cartant Jul 13 '17 at 04:54
  • you write your own validator, is your concern that it will be applied on each change instead of each 500 ms? – Max Koretskyi Jul 13 '17 at 05:11
  • @cartant Well, so from what I understand it's not possible to achieve it the way I'm looking for because validators are not implemented as Observable objects in Angular – Bil5 Jul 13 '17 at 05:14
  • @Maximus Not only, I know we can do the same with promises and timeouts, but Observable has so many useful handlers it would be great to be able to use – Bil5 Jul 13 '17 at 05:15
  • an async validator can return an observable as well, not only promise – Max Koretskyi Jul 13 '17 at 05:19
  • @maximus That is what the static method checkAsyncValue of my example do, but, in this case how to make use of debounceTime(500).distinctUntilChanged() without observing manually issueSubject.valueChanges? could you provide an example? – Bil5 Jul 13 '17 at 05:23
  • what is the reason for using `debounceTime(500).distinctUntilChanged()` in your case for this particular control? – Max Koretskyi Jul 13 '17 at 05:36
  • @Maximus The reason is to avoid asking server too frequently or for the same value 2 times. The call to server is emulated by a timeout in my example. I know there are way to do it without Observable but this is not what I'm looking for – Bil5 Jul 13 '17 at 05:45
  • 1
    check [this](https://stackoverflow.com/questions/36919011/how-to-add-debounce-time-to-an-async-validator-in-angular-2) and [this](https://github.com/angular/angular/issues/6895) – Max Koretskyi Jul 13 '17 at 05:52
  • @Maximus Thanks for the links, happy to see a lot of people facing the same situation. I see different implementations that could potentially work but one thing seems to be sure: that's not as simple as I expected it to be. Quite surprising (and disappointing) that Angular2 (inside which RxJS paradigm occupies a central place) hasn't made things more natural with Observables – Bil5 Jul 13 '17 at 06:51
  • it's not about observables, it's how form control <-> native input integration takes place – Max Koretskyi Jul 13 '17 at 06:55
  • @Maximus I may be wrong but if FormControl's were automatically registering Observable validators on valueChanges then the problem would be solved. I mean for example: fb.control('', [], [ObsValidator1, ObsValidator2]]) Then the framework would have to do something like : formControl.getObservableValidators().forEach(observer){ formControl.valueChanges.switchMap( (control) => observer(control)); } – Bil5 Jul 13 '17 at 08:31

0 Answers0