3

I have a form with a "name" control.

<div class="field">
  <label>Name</label>
  <input ngControl="name">
  <p *ngIf="name.pending">
    Fetching data from the server...
  </p>
  <div *ngIf="!name.valid && !name.pending"
    class="ui error message">Name is not valid</div>
</div>

The control is built with FormBuilder like this :

this.name = fb.control('', null, this.characterNameValidator.bind(this));

and I created a validator :

characterNameValidator(control: Control) {
    let q = new Promise((resolve, reject) => {
        setTimeout(() => {
            if (this._characterService.isCharacterNameAlreadyExists(control.value)) {
                resolve({nameCharacterAlreadyExistsError: true});
            } else {
                resolve(null);
            }
        }, 1000)
    });

    return q;
}

On each keystroke, my validator is called. I'm looking for a way to call the validator only after a debounce time.

I try with valueChanges(), but I understand only if I call a specific service but not in the case of validation.

Edit

Is it a good idea to manage validation manually to achieve my problem ? I don't put a validator in my control but I set errors manually on valueChanges.

this.name = fb.control('');

this.name.valueChanges.debounceTime(400).subscribe(() => {
  this.characterNameValidator(this.name).then((validationResult => {
    this.name.setErrors(validationResult)
  }))
});
Kelem
  • 123
  • 1
  • 7
  • Looks like the same requirement as http://stackoverflow.com/questions/33799600/general-asynchonious-validation-in-angular2 – Günter Zöchbauer Feb 08 '16 at 20:01
  • See https://github.com/angular/angular/issues/6895 including a full solution for this exact scenario. Hopefully there will be native support added related to that ticket in v4 – Matthew Erwin Apr 01 '17 at 04:23

2 Answers2

2

See https://github.com/angular/angular/issues/1068 for a related open issue.

If you pass a reference to the control to the validator you could use something like

this.formGp.controls['numberFld'].updateValueAndValidity();

from https://stackoverflow.com/a/33377290/217408

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
1

The official way of getting what you want is in upcoming features to form validation.

https://youtu.be/kM5QBOWrUVI?t=9m48s

However, you can manually debounce validation by subscribing to value changes, and setting your own error.

testForm.controls['name'].valueChanges
.do(
    res => {
        if (res) {
            this.testForm.controls['name'].setErrors({loading: true});
        }
    }
)
.debounceTime(500)
.subscribe(
    res => {
        if (this.nameSub) {
            this.nameSub.unsubscribe();
            this.nameSub = null;
        }

        this.nameSub = this.http.get(apiURL + 'exist/?name=' + res).subscribe(
            exists => {
                this.testForm.controls['name'].setErrors({nameExists: true});
                this.nameSub.unsubscribe();
                this.nameSub = null;
            },
            error => {
                if (res) {
                    this.testForm.controls['name'].setErrors(null);
                }
                this.nameSub.unsubscribe();
                this.nameSub = null;
            }
        );
    },
    error => {}
);
Brenton
  • 317
  • 2
  • 9