5
respostas

Validação de formulário por métodos assíncronos em Angular

Erro abaixo na hora de validar um campo do formulário com método assíncrono:

import { AbstractControl } from '@angular/forms';
import { VerificaEmailService } from './verifica-email-service';
import { Injectable } from '@angular/core';
import { debounceTime, switchMap, map, first } from 'rxjs/operators';

@Injectable({  providedIn: 'root'})
export class EmailTakenValidationService {

    constructor(private verificaEmailService: VerificaEmailService) {}

    checkEmailTaken(){

      return (control: AbstractControl) => {
        return control
          .valueChanges
          .pipe(debounceTime(500))
          .pipe(switchMap(email => {
              return this.verificaEmailService.verificarEmail(email);
          }))
          .pipe(map(isTaken => isTaken ? {emailTaken: true } : null))
          .pipe(first());
      };
    }
}
(control) => { return control .valueChanges .pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_0__["debounceTime"])(500)) .pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_0__["switchMap"])(email => { return this.verificaEmailService.verificarEmail(email); })) .pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_0__["map"])(isTaken => isTaken ? { emailTaken: true } : null)) .pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_0__["first"])()); }
5 respostas

Fala ai Matias, tudo bem? Posso te pedir um favor? Compartilha o projeto completo, assim eu consigo simular o problema por aqui e analisá-lo com mais calma.

Pode compartilhar através do Github ou Google Drive (zipado).

Espero ter ajudado.

Olá, é a mesma ideia do código da aula: https://s3.amazonaws.com/caelum-online-public/901-angular-parte2/stages/12-alurapic.zip

No código ele faz o seguinte:

 <ap-vmessage 
      text="Username already taken" 
      *ngIf="signupForm.get('userName').errors?.userNameTaken">
  </ap-vmessage> 
ngOnInit(): void {
        this.signupForm = this.formBuilder.group({
            email: ['', 
                [
                    Validators.required,
                    Validators.email
                ]
            ],
            fullName: ['', 
                [
                    Validators.required,
                    Validators.minLength(2),
                    Validators.maxLength(40)
                ]
            ],
            userName: ['', 
                [
                    Validators.required,
                    lowerCaseValidator,
                    Validators.minLength(2),
                    Validators.maxLength(30)
                ],
                this.userNotTakenValidatorService.checkUserNameTaken()
            ],
            password: ['', 
                [
                    Validators.required,
                    Validators.minLength(8),
                    Validators.maxLength(14)
                ]
            ]
        });
    } 
    checkUserNameTaken() {
        return (control: AbstractControl) => {
            return control
                .valueChanges
                .pipe(debounceTime(300))
                .pipe(switchMap(userName => 
                        this.signUpService.checkUserNameTaken(userName)
                ))
                .pipe(map(isTaken => isTaken ? { userNameTaken: true } : null))
                .pipe(tap(r => console.log(r)))
                .pipe(first());
        }
    }
 checkUserNameTaken(userName: string) {
        return this.http.get(API_URL + '/user/exists/' + userName);
    }

Quero fazer assim só que eu retorno do servidor um boolean para verificar se existe ou não, na aula ele retorna um objeto User.

onde tenho que modificar no método checkUserNameTaken para tratar esse boolean que vem do servidor?

Fala ai Matias, tudo bem? Na realidade hoje a API ja retorna um booleano:

.pipe(switchMap(userName => 
                        this.signUpService.checkUserNameTaken(userName)
                ))

Que será o isTaken do próximo pipe, no caso:

.pipe(map(isTaken => isTaken ? { userNameTaken: true } : null))

Aqui, seria bom você continuar com um objeto, porque no template é necessário para ler o erro:

*ngIf="signupForm.get('userName').errors?.userNameTaken"

Repare que temos errors?.userNameTaken onde o userNameTaken é exatamente o que foi retornado no pipe acima.

Espero ter ajudado.

Entendi, era meu servidor que retornava um objeto. Por segurança é melhor retornar um boolean mesmo. O método checkUserNameTaken funciona perfeitamente.

Boa Matias, é isso ai.

Sempre que precisar não deixe de criar suas dúvidas.

Abraços e bons estudos.