Validação de formulário com ngModel - Angular
Como construir uma validação de formulário direto no template através do uso da diretiva ngModel.
Em um outro post, Validação de formulário utilizando o ReactiveFormsModule do Angular 2+, foi apresentado como podemos construir uma validação de formulário utilizando alguns recursos como FormGroup
, FormControl
, FormBuilder
, entre outros. Neste texto vamos abordar uma outra forma de construir validação de formulários com o uso da diretiva ngModel
.
Introdução
Considere o template abaixo:
<form (ngSubmit)="postar()">
<div>
<input type="text"
name="nome"
placeholder="Nome..." />
</div>
<div>
<button type="submit">
Enviar
</button>
</div>
</form>
Quando o botão Enviar
for clicado, o formulário sofrerá um post e o método postar()
será chamado.
Neste exemplo não estamos enviando os dados do formulário para o método postar()
e também não estamos validando nenhuma informação.
Para facilitar o trabalho e podermos pegar os dados dos campos do formulário e também fazer uma validação, vamos criar uma instância do FormControl e vinculá-lo ao input através do uso da diretiva ngModel.
Diretiva ngModel
O primeiro passo é garantir que o módulo do seu componente tenha importado o FormsModule
. Neste artigo os códigos de exemplo serão incluídos nos componentes Exemplo1Component
e Exemplo2Component
que estão declarados no AppModule
. Logo, temos que importar o FormsModule
no AppModule
conforme o exemplo abaixo:
Vamos declarar um método dentro da classe para sabermos que o formulário foi postados e na sequência abordaremos seu template:
Agora voltamos a atenção para o template. Vamos adicionar a diretiva ngModel
no input
para criar um FormControl
:
Para pegarmos a referência desta diretiva, ngModel
, podemos escrever algo do tipo: #minhaVariavel="ngModel"
.
Lembre-se de que durante a criação de uma diretiva podemos preencher a propriedade exportAs
para definir um nome, um nome que possa ser utilizado no template para pegarmos a instância da diretiva. No caso do ngModel
é "ngModel"
.
Fonte: https://angular.io/api/core/Directive#exportas
To inspect the properties of the associatedFormControl
(like the validity state), export the directive into a local template variable usingngModel
as the key (ex:#myVar="ngModel"
). You can then access the control using the directive'scontrol
property. However, the most commonly used properties (likevalid
anddirty
) also exist on the control for direct access. See a full list of properties directly available inAbstractControlDirective
.
https://angular.io/api/forms/NgModel#description
Seguindo a lógica acima:
No template acima criamos um FormControl
vinculado ao nosso único input
e passamos sua referência para a variável formNome
. Então vamos testar se realmente formNome: FormControl
está configurado corretamente adicionando alguns trechos a mais:
Podemos observar no resultado abaixo que conseguimos acessar o valor do input
bem como outras informações como valid
e errors
:
Iniciando a validação do input
Agora vamos evoluir um pouco mais e adicionar algumas validações e melhorias:
- O campo
nome
é obrigatório - O campo
nome
deve ter pelo menos 3 caracteres - O botão
Enviar
deve ficar desabilitado caso o camponome
tenha um valor inválido
As alterações são efetuadas direto no template:
Veja no resultado abaixo que toda vez que digitamos algo no input
:
- o
formNome.value
muda conforme o valor doinput
; - o
formNome.valid
ouformNome.invalid
muda conforme o valor doinput
fica válido/inválido. Veja que o botãoEnviar
as vezes fica verde (habilitado) e as vezes cinza (desabilitado) - o
formNome.errors
muda conforme os erros de validação mudam. Quando não há erros, ou seja, o valor é válido, oformNome.errors
apresentanull
Para finalizar precisamos:
- pegar o valor deste
input
e passar para o métodopostar
- adicionar algumas mensagens de validação para ajudar o usuário
Alterando o método postar
para receber um parâmetro (nome
):
Alterando o template para incluir as mensagens de validação e também passar o valor do input
no método postar
:
Validação de múltiplos campos
Vamos adicionar mais um campo: sobrenome
. Basicamente vamos duplicar o conteúdo do <input name="nome" ...
.
Na classe vamos adicionar mais um parâmetro no método postar
para receber o sobrenome
:
No template duplicamos toda a lógica envolvendo o input nome
e criamos o input sobrenome
:
Veja que apenas duplicamos os inputs ajustando os respectivos nomes. Aqui temos alguns pontos importantes:
- Agora o botão
Enviar
analisa dois valores ao invés de um para saber se deve ficar desabilitado ou habilitado - No
(ngSubmit)
do formulário estamos passando dois campos ao invés de 1
Imagine que este formulário poderá crescer contento diversos campos. Ficará um pouco inviável seguir nesta linha. Para resolver este problema vamos utilizar um FormGroup
no <form>
através da sintaxe #minhaVariavel="ngForm"
.
Vamos alterar o parâmetro do método postar
. Agora receberá um objeto contendo um nome e um sobrenome:
No template as alterações são pequenas:
- Incluir o
FormGroup
no<form>
- Ajustar a chamada do método
postar
- Ajustar o
[disabled]
do botãoEnviar
Resultado:
Criando estilos baseados no estado
Agora que o formulário está funcionando corretamente, vamos focar no estilo visual.
Repare na imagem acima que há uma barra à esquerda do formulário que muda de cor conforme seu estado (válido/inválido). Conseguimos chegar neste efeito utilizando algumas classes CSS (tabela abaixo) que o Angular injeta tanto no <form>
quando nos inputs
que recebem o ngModel
.
State | Class if true |
Class if false |
---|---|---|
The control has been visited | ng-touched |
ng-untouched |
The control's value has changed | ng-dirty |
ng-pristine |
The control's value is valid | ng-valid |
ng-invalid |
Então para saber se o formulário está válido ou inválido podemos utilizar ng-valid
e ng-invalid
conforme o CSS abaixo:
form.ng-valid {
border-left: 4px solid #4CAF50;
}
form.ng-invalid {
border-left: 4px solid #f44336;
}
Veja na imagem abaixo para entender melhor:
Considerações
Este recurso é extremamente útil para criar validações de forma bem rápida e eficiente. Não cheguei a abordar o two way data binding ([(ngModel)]="variavel"
), mas caso tenha interesse em saber mais sobre o assunto: https://angular.io/guide/two-way-binding.
Caso você não esteja tão familiarizado com validações utilizando Angular, sugiro dar uma lida nestes posts:
- https://consolelog.com.br/validacao-de-formulario-utilizando-o-reactiveformsmodule-do-angular-2/
- https://consolelog.com.br/validacao-componente-customizado-angular/
Links: