Home > Software design >  Why is my custom validator not updating my FormControl?
Why is my custom validator not updating my FormControl?

Time:12-22

I have a Redux-SPA with a Messaging System with mailboxes (basically just folders). When the user wants to create a new mailbox (folder), a dialog gets shown where the user can enter a new mailbox name. To prevent unnecessary API calls, I look into the state to see if the mailbox/folder does already exist. If yes, I want to invalidate the form and disable the "Create" button.

I have already made sure that the function returns the correct values via the tap(). The control is invalidated correctly if it is empty, so the default validator works correctly. Just my custom validator is not working somehow.

Where is my error? What can I try to debug further?

This is my code:

@Component({
  selector: 'app-new-mailbox-dialog',
  templateUrl: 'new-mailbox-dialog.component.html',
})
export class NewMailboxDialogComponent implements OnInit {
  formControl: FormControl = new FormControl('', [Validators.required], this.mailboxNameExists.bind(this));

  constructor(
    public dialogRef: MatDialogRef<NewMailboxDialogComponent>,
    private messagingFacade: MessagingFacade
  ) {}

  ngOnInit() {}

  onNoClick(): void {
    this.dialogRef.close();
  }

  mailboxNameExists(control: FormControl): Observable<ValidationErrors | null> {
    return this.messagingFacade.getMailboxesList$.pipe(
      tap(() => console.log(control.value)),
      map(names => names.find(mailbox => mailbox.designation === control.value)),
      map(exists => exists ? { mailboxNameExists: true } : null)
      tap(value => console.log(value)),
    );
  }
}

CodePudding user response:

I usually write my AsyncValidatorFn streams/method as follows:

validator(): AsyncValidatorFn {
    return (control: AbstractControl): Observable<ValidationErrors | null> => {
      if (!control.value || control.pristine) {
        return of(null);
      }
      
      return control.valueChanges.pipe(
        debounceTime(300),
        distinctUntilChanged(),
        take(1),
        switchMap(value => {
          return this.messagingFacade.getMailboxesList$;
        }),
        catchError(err => of(null)),
        map(response => {
            return response ? { error: true } : null;
          }),
        finalize(() => {
          control.markAsTouched();
          this.ref.markForCheck();
        })
      );
    };
  }

Not sure you need the finalize, I have this usually do to the detection strat.

Also in the template, which you do not show I am normally checking for touched and invalid along with the errors to show the error message.

CodePudding user response:

you can try using the of method

MessagingFacade TS:

getMailboxesList$ = of([{designation: 'test'}])
  • Related