2
votes

I have build a Custom Validator for my Form, which returns expected ValidationErrors object.

ValidateDirectory(clientId: string): ValidatorFn {
        return (control: AbstractControl): ValidationErrors | null => {
            const ret: ValidationErrors = { isValidDirectory: true };
            if (control.value == null || control.value === '') {
                return ret;
            }
            this.service.getList(clientId, control.value).subscribe((res) => {
                if (res.technicalRetCode !== 0) {
                    console.log(ret);
                    return ret;
                }
                return null;
            });
            return null;
        };
    }

I proved this with console.log line, this actually logs my object.

The Validator is attached besides a Validators.required in ngOnInit

ngOnInit() {
  ...
  this.fourthFormGroup = this._formBuilder.group({
      dateipfad: ['', {validator: Validators.compose([Validators.required, this.directoryValidator.ValidateDirectory(this.clientID)]), updateOn: 'blur'}]
    });
  ... 
}

Problem is: the required Validator works as intended, but my custom Validator just logs.

I have tried quite a lot, like using validators with array instead of Validators.compose, tweaked my Validator method to set control.setErrors(ret) some other things, nothing worked.

I feel like there is quite a simple solution, but I just can't find it...

EDIT 1: I created a stackblitz https://stackblitz.com/edit/angular-ysyb9i?file=src%2Fapp%2Fapp.component.html

Explanation: the input takes any strings, on deselect the validation kicks in. if Input is 'false' it should set input to invalid by returning const ret: ValidationErrors = { isValidDirectory: true };, any other string should be valid and it returns null.

Both results are logged on console, so you can check it. If input is invalid it should show a notification div below (not quite sure, just added it for this stackblitz to show)

1
Can you please create a stackblitz that will replicate your issue?yurzui
sure, gonna take some timeMagelan
@yurzui I edited my Question with stackBlitz link. It's the first time I use it, so have mercy ;)Magelan
Try this updated stackblitz stackblitz.com/edit/angular-vjgqex?file=src/app/… It works for me. Just one note, if your validator is async then you should put it to async validatorsyurzui
Thanks for your help! This helps for the initial validation, but after you enter 'false' you don't get the invalid flag. I didn't work with async validators yet, but it seems the solution is to do this validator async.Magelan

1 Answers

1
votes

You should be using async validator if the code inside your validator is async.

this.fourthFormGroup = this._formBuilder.group({
  dateipfad: ['', {
    validators: [Validators.required],
    asyncValidators: [this.directoryValidator.ValidateDirectory(this.clientID)],
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                    put it here
    updateOn: 'blur'
  }]
});

The validator should return AsyncValidatorFn interface where you should subscribe to observable but rather map to the value you want. Angular will subscribe automatically to your observable.

ValidateDirectory(clientId: string): AsyncValidatorFn {
  return (control: AbstractControl): 
             Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
    const ret: ValidationErrors = { isValidDirectory: true };

    if (control.value == null || control.value === '') {
      return of(ret);
    }

    return this.service.getList(clientId, control.value).pipe(map((res: any) => {
      if (res.technicalRetCode !== 0) {
        return ret;
      }

      return null;
    }));
  };
}

Forked Stackblitz

Also please do note that async validators are fired only when all sync validators return null. So you won't see the error from the start because you have synchronous required validator in place.