Dominando as validações customizadas no Angular
No desenvolvimento de aplicações Angular, a validação de dados de formulários é uma etapa crucial para garantir a integridade e a qualidade dos dados manipulados pelo sistema.
Embora o Angular ofereça validações integradas, muitas vezes precisamos de validações personalizadas para atender a requisitos específicos. Neste artigo, exploraremos o mundo das validações customizadas no Angular, abordando validações síncronas e assíncronas, permitindo que você crie validações robustas e adaptadas às necessidades do seu projeto.
Validações de formulários com Reactive Forms
Os Reactive Forms oferecem uma abordagem flexível e poderosa para a validação de dados dos seus formulários. Podemos iniciar um formulário utilizando a classe FormGroup
para criar um grupo de controles que representam os campos do seu formulário.
Utilizando o serviço FormBuilder
, conseguimos facilmente integrar as validações dentro de um array para cada campo. Na primeira posição indicamos qual será o valor inicial, na segunda posição informamos as validações síncronas, e na terceira posição informamos as validações assíncronas. Observe a aplicação de todos os validadores no campo username
.
Validações síncronas
As validações síncronas são aquelas que podem ser avaliadas instantaneamente sem a necessidade de consultas externas. O próprio Angular já disponibiliza diversos validadores síncronos dentro da classe Validators, como por exemplo required, minLength, maxLength e email.
Vamos entender como podemos criar nossos próprios validadores customizados.
Validador sem parâmetros
Quando você precisa criar um validador simples que não necessita de valores dinâmicos, basta criar uma função que aceite um parâmetro do tipo AbstractControl
(ou um controle mais específico) e retorne um objeto se a validação falhar, ou null
se passar.
No exemplo acima, criamos um validador de um campo Required, mesmo que ele possua espaços em branco.
Para integrá-lo no formulário é bastante simples. Basta utilizar esta função no controle, onde é possível anexar validadores síncronos.
No validador, criamos uma regra para retornar o objeto {required: true}
caso o campo estiver inválido. Sabendo disso, podemos usar essa propriedade para dar um feedback visual para o usuário:
Validador como parâmetros
Existem casos onde precisamos passar valores dinâmicos para nossos validadores. Um bom exemplo é a utilização dos validadores minLength e maxLength, onde precisamos informar qual é o tamanho mínimo e tamanho máximo permitido, respectivamente.
Para criar um validador customizado com este requisito, precisamos criar uma factory function que vai receber os valores dinâmicos. Esta factory function irá retornar uma outra função que conterá a lógica de validação.
Se esta prática soa estranha pra você, então recomendo ler sobre Higher Order Functions.
Este validador checa se um nome é válido ou não dependendo de uma expressão regular passada via parâmetro. Na integração do formulário, podemos então informar este parâmetro.
No exemplo acima, o nome proibido é bob. Então o validador rejeitará qualquer nome que contenha bob.
Validações assíncronas
Em alguns cenários, as validações podem depender de chamadas assíncronas, como a validação em tempo real de disponibilidade de nomes de usuário.
É importante ressaltar que geralmente quando precisamos realizar chamadas assíncronas, é necessário o uso da Injeção de Dependência no Angular. Portanto é comum nestes casos passarmos uma Service via parâmetro para o validador.
Perceba que desta vez estamos passando uma service chamada UserService por parâmetro da factory function. Ela possui um método chamado getByName, responsável por fazer uma consulta no servidor, retornando o usuário encontrado ou vazio. Para o validador se comportar da maneira esperada, utilizamos o operador map
do RxJS para transformar o resultado no objeto {uniqueName:true}
(caso o nome já exista) ou então null
(caso o nome não exista).
Observação: podemos utilizar tanto
Promises
comoObservables
para validadores assíncronos. Apenas lembre-se que o retorno deve ser um objeto de erro ounull
.
Para integrá-lo no formulário precisamos utilizar esta função no controle, onde é possível anexar validadores assíncronos. Um ponto importante é o UserService passado por parâmetro. Para que funcione corretamente é necessário injetar esta service no componente.
Uma vez que a validação inicia, uniqueUserValidator delega ao método getByName() o valor do controle atual. Por ser uma operação assíncrona, enquanto o resultado não é obtido, o Angular marca este controle como pending
. Isso é muito útil para dar um feedback para o usuário de que a consulta está sendo feita e ele deve aguardar. Após o termino da operação, o Angular atualiza o controle, informando se de fato o controle está válido ou inválido, com base na regra imposta pelo validador customizado.
Conclusão
Dominar as validações customizadas no Angular é uma habilidade valiosa para qualquer desenvolvedor. A capacidade de criar validações que se alinham perfeitamente às necessidades do seu projeto é fundamental para garantir a qualidade e a confiabilidade das interações do usuário. Neste artigo, exploramos tanto as validações síncronas quanto as assíncronas, fornecendo uma base sólida para você começar a criar validações personalizadas de maneira eficaz.
Lembre-se de que o uso de validações personalizadas deve ser equilibrado com boas práticas de UX, fornecendo feedback claro e útil aos usuários para melhorar a experiência geral da aplicação.