0

I am trying to verify if a name is present in the database. If so, I want to mark it as invalid and inform to the user this occurrence.

Besides this, I'm looking for the best approach to do this: template driven forms or reactive forms.

Note that I'm using multiple forms like the examples in https://material.angular.io.

Here's my current code:

HTML:

<mat-horizontal-stepper [@.disabled]="true" #stepper>
  <mat-step label="Example" [stepControl]="nameForm">
    <form [formGroup]="nameForm">
      <mat-form-field>
        <mat-label>NAME</mat-label>
        <input matInput placeholder="Input name" formControlName="name">
      </mat-form-field>
      <button
        matTooltip="Verify name in data base"
        (click)="validateName()" <<<< LOOK, HERE IS THE POINT
        [disabled]="!loading">Validate Name
        <i class="ml-2 fa fa-refresh fa-spin" *ngIf="!loading"></i>
      </button>

      <div>
        <button mat-button matStepperNext>Next</button>
      </div>
    </form>
  </mat-step>

  <mat-step label="Endereço" [stepControl]="enderecoForm">
    <form [formGroup]="nameForm2">
      <mat-form-field>
        ...
      </mat-form-field>
    </form>
  </mat-step>

... more steps with one form inside of each one

TS:

export class SomeComponent {
  constructor(private readonly _formBuilder: FormBuilder) {}

  ngOnInit(): void {
    this.nameForm = this._formBuilder.group(
      {
        name: ['', Validators.required],
      },
      { validator: this.validateName },
    ); // AND HERE LOOK
    this.nameForm2 = this._formBuilder.group({
      name2: ['', Validators.required],
      // ... more forms and controls validators with reactive forms
    });
  }

  validateName(fb: FormGroup) {
    const nameCtrl = fb.get('name');
    // method verifyName return the name from database if exists
    const name = this.nameService.verifyName(nameCtrl);

    if (nameCtrl.errors == null || 'exists' in nameCtrl.errors) {
      if (name == null) {
        nameCtrl.setErrors(null);
      } else {
        nameCtrl.setErrors({ exists: true });
      }
    }
  }
}
2
  • Excuse me, can you answer me these questions: from where comes the variable confirmSenhaCtrl? Do you want to validate only after button click? Could you post at least the signature of the nameServive.verifyName function? Commented May 14, 2020 at 2:26
  • sorry, i fix it , updated. Commented May 14, 2020 at 15:01

1 Answer 1

3

I don't quite understand if you want to validate using AsyncValidator or after clicking a button, but here we go:

1. To validate through asyncValidators:

import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';

import { Observable, of as just } from 'rxjs';
import { catchError } from 'rxjs/operators';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-some',
  templateUrl: './some-component.html'
})
export class SomeComponent {
  readonly formGroup = this.formBuilder.group(
    {
      name: ['', Validators.required, this.validateName]
    },
    { updateOn: 'blur' }
  );

  constructor(private readonly formBuilder: FormBuilder) {}

  // For this case, I'd suggest you to name it something like `nameAsyncValidator`.
  // In any case it's up to you :)
  private validateName(): Observable<{ exists: boolean } | null> {
    const { errors, value } = this.formGroup.get('name')!;

    if (errors || !value) return just(null);

    return this.nameService.verifyName(value).pipe(
      catchError(() => just(null))
    );
  }
}

2. To validate through a button click:

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';

import { catchError, take, tap } from 'rxjs/operators';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-some',
  templateUrl: './some-component.html'
})
export class SomeComponent {
  readonly formGroup = this.formBuilder.group({
    name: ['', Validators.required]
  });

  validateName(): void {
    const nameFormControl = this.formGroup.get('name')!;
    const { errors, value } = nameFormControl;

    if (errors || !value) return;

    return this.nameService.verifyName(value).pipe(
      take(1),
      catchError(() => just(null)),
      tap(exists => nameFormControl.setErrors(exists))
    )
    .subscribe();
  }
}

Note that as you didn't include the signature of the nameServive.verifyName in the question, I assumed that it returns Observable<{ exists: boolean } | null>.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks brother, the second aproach with the button validation is what i've looking for 😀😀

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.