0

I have setup the updateOn of my form on "blur" (ngOnInit):

    this.formStepper = this._fb.group({
      steps: this._fb.array([
        this._fb.group({
          email: [
            this.formDataMail.dataValue,
            {
              updateOn: 'blur',
              validators: [Validators.required, Validators.email],
            },
          ],
        }),
        new FormGroup({}),
      ]),
    });

To manually valid my input (ngAfterViewInit) :

    fromEvent(this.emailInput.nativeElement, 'keyup')
      .pipe(
        filter(Boolean),
        debounceTime(600),
        distinctUntilChanged(),
        tap((_) => {
          this.formArray.at(0).get('email').updateValueAndValidity();
        })
      )
      .subscribe();

This should update the form value and display an error according to my validators but instead of that my form value remains null until I blur.

    this.formArray
      .at(0)
      .valueChanges.pipe(
        takeUntil(this._onDestroy$),
        tap((changes: string ) => {
          // changes value is synchronized with blur action even if I call updateValueAndValidity function
        })
      )
      .subscribe();

Why does updateValueAndValidity not update the value as mentioned ?

Thank you very much

As a workaround, I tried to update the value manually and mark the form as dirty to display errors message before the first blur action

    fromEvent(this.emailInput.nativeElement, 'keyup')
      .pipe(
        filter(Boolean),
        debounceTime(600),
        distinctUntilChanged(),
        tap((_) => {
          this.formArray
            .at(0)
            .get('email')
            .setValue(this.emailInput.nativeElement.value);
          this.formArray.at(0).get('email').markAsDirty();
          this.formArray.at(0).get('email').updateValueAndValidity();
        })
      )
      .subscribe();
imGok
  • 29
  • 6
  • Maybe I'm missing something, you've configured the form to update on blur, but you're confused as to why it's only updating when you blur the input? Why not use the regular update strategy? You are already simulating the normal update strategy by running validation on every keystroke. The reason you need to call `markAsDirty()` is that it blurs the input, and then the value reaches the form control. – Meqwz Jan 18 '23 at 16:05
  • The idea is to get the error message once the user stops writing or unfocus the input. We don't want to get the error message while the user has not finished to type his email. I'm not simulating the normal update since I put a debounceTime – imGok Jan 18 '23 at 16:56

1 Answers1

0

I think this approach is far too complicated. I propose the following solution.

1.) Remove updateOn: 'blur'

    this.formStepper = this._fb.group({
      steps: this._fb.array([
        this._fb.group({
          email: [
            this.formDataMail.dataValue,
            {
              validators: [Validators.required, Validators.email],
            },
          ],
        }),
        new FormGroup({}),
      ]),
    });

2.) Set up your errors to display when the input is touched (meaning on blur):

    <mat-error *ngIf="formArray.at(0).get('email').hasError('email') && !formArray.at(0).get('email').hasError('required')">
      Please enter a valid email address
    </mat-error>
    <mat-error *ngIf="formArray.at(0).get('email').hasError('required')">
      Email is <strong>required</strong>
    </mat-error>

3.) Subscribe to the changes of the input and mark the input as touched after 600ms of debounce time:

    this.formArray.at(0).get('email').valueChanges.pipe(debounceTime(600)).subscribe(() => {
      this.formArray.at(0).get('email').markAsTouched();
    });

StackBlitz here.

Meqwz
  • 1,319
  • 8
  • 14