Artigo original: How to Validate Angular Reactive Forms
Introdução
Neste artigo, aprenderemos sobre a validação de formulários reativos em Angular. Criaremos um formulário simples de registro de usuário e implementaremos algumas validações integradas nele. Juntamente com as validações integradas, também vamos implementar algumas validações personalizadas para o formulário reativo.
Consideraremos as seguintes validações personalizadas para esta demonstração:
- Verificar a disponibilidade do nome do usuário
- Validar o padrão de senha
- Validar a senha digitada em dois campos diferentes
Veja a aplicação em ação:

Pré-requisitos
- Instalar o Visual Studio Code por este link
- Instalar a versão mais atualizada da Angular CLI por este link
Código-fonte
Obtenha o código-fonte pelo GitHub.
Criando a aplicação em Angular
Navegue até a pasta onde deseja criar seu arquivo de projeto. Abra uma janela de comando e execute o comando mostrado abaixo:
ng new angular-forms-validation --routing=false --style=scss
Estamos especificando o comando para criar uma nova aplicação em Angular. A opção de criar o módulo de roteamento é definida como falsa e a extensão de arquivos de estilo é definida como scss
. Este comando criará o projeto em Angular com o nome de angular-forms-validation
.
Altere os diretórios, vá para o novo projeto e abra-o no Visual Studio Code usando os comandos mostrados abaixo:
cd angular-forms-validation
code .
Instalando o Bootstrap
Execute o comando abaixo para instalar a biblioteca do Bootstrap na pasta do projeto:
npm install bootstrap --save
Adicione a seguinte definição de importação no arquivo styles.scss
:
@import "~bootstrap/dist/css/bootstrap.css";
Criando o serviço de validação
Execute o comando abaixo para criar um novo serviço:
ng g s services\customvalidation
Este comando criará uma pasta nomeada serviços com dois arquivos — customvalidation.service.ts
e customvalidation.service.spec.ts
. Abra o arquivo customvalidation.service.ts
e cole o código abaixo:
import { Injectable } from '@angular/core';
import { ValidatorFn, AbstractControl } from '@angular/forms';
import { FormGroup } from '@angular/forms';
@Injectable({
providedIn: 'root'
})
export class CustomvalidationService {
patternValidator(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } => {
if (!control.value) {
return null;
}
const regex = new RegExp('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9]).{8,}$');
const valid = regex.test(control.value);
return valid ? null : { invalidPassword: true };
};
}
MatchPassword(password: string, confirmPassword: string) {
return (formGroup: FormGroup) => {
const passwordControl = formGroup.controls[password];
const confirmPasswordControl = formGroup.controls[confirmPassword];
if (!passwordControl || !confirmPasswordControl) {
return null;
}
if (confirmPasswordControl.errors && !confirmPasswordControl.errors.passwordMismatch) {
return null;
}
if (passwordControl.value !== confirmPasswordControl.value) {
confirmPasswordControl.setErrors({ passwordMismatch: true });
} else {
confirmPasswordControl.setErrors(null);
}
}
}
userNameValidator(userControl: AbstractControl) {
return new Promise(resolve => {
setTimeout(() => {
if (this.validateUserName(userControl.value)) {
resolve({ userNameNotAvailable: true });
} else {
resolve(null);
}
}, 1000);
});
}
validateUserName(userName: string) {
const UserList = ['ankit', 'admin', 'user', 'superuser'];
return (UserList.indexOf(userName) > -1);
}
}
O método patternValidator
é usado para validar o padrão de senha em nosso formulário. O parâmetro para este método é o tipo AbstractControl
, que é uma classe base para FormControl
.
Usaremos uma expressão regular para validar a senha. Validaremos as quatro condições a seguir usando a expressão regular:
- A senha deve ter um mínimo de oito caracteres.
- Precisa ter pelo menos uma letra minúscula.
- Precisa ter pelo menos uma letra maiúscula.
- Precisa ter pelo menos um número.
Se a senha falhar na verificação pela regex, definiremos a propriedade invalidPassword
como verdadeira.
O método MatchPassword
é usado para comparar as senhas em dois campos. Este método aceitará dois parâmetros do tipo String. Estes parâmetros representam o nome dos campos a serem correspondidos. Pegaremos o FormControl
para esses dois campos e, em seguida, igualaremos os valores neles. Se os valores não coincidirem, definiremos a propriedade passwordMismatch
como verdadeira.
O método userNameValidator
é usado para verificar se o nome de usuário já foi usado anteriormente ou não. Este método aceitará um parâmetro do tipo AbstractControl
. Verificaremos se o valor deste campo está presente em um array estático, UserList
. Se o valor inserido pelo usuário já estiver presente, definiremos a propriedade userNameNotAvailable
como verdadeira.
Estamos usando a função setTimeout
para executar esta verificação a cada dois segundos. Isso garantirá que o erro será acionado após dois segundos a partir do momento em que o usuário parar de digitar no campo.
Para simplificar este artigo, estamos usando um array estático para pesquisar a disponibilidade de nomes de usuário. Idealmente, deveria ser uma chamada de serviço ao servidor para pesquisar o valor em um banco de dados.
Criando o componente reactive-form
Execute o seguinte comando para criar o componente reactive-form:
ng g c reactive-form
Abra reactive-form.component.ts
e cole o código abaixo:
import { Component, OnInit } from '@angular/core';
import { Validators, FormGroup, FormBuilder } from '@angular/forms';
import { CustomvalidationService } from '../services/customvalidation.service';
@Component({
selector: 'app-reactive-form',
templateUrl: './reactive-form.component.html',
styleUrls: ['./reactive-form.component.scss']
})
export class ReactiveFormComponent implements OnInit {
registerForm: FormGroup;
submitted = false;
constructor(
private fb: FormBuilder,
private customValidator: CustomvalidationService
) { }
ngOnInit() {
this.registerForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
username: ['', [Validators.required], this.customValidator.userNameValidator.bind(this.customValidator)],
password: ['', Validators.compose([Validators.required, this.customValidator.patternValidator()])],
confirmPassword: ['', [Validators.required]],
},
{
validator: this.customValidator.MatchPassword('password', 'confirmPassword'),
}
);
}
get registerFormControl() {
return this.registerForm.controls;
}
onSubmit() {
this.submitted = true;
if (this.registerForm.valid) {
alert('Form Submitted succesfully!!!\n Check the values in browser console.');
console.table(this.registerForm.value);
}
}
}
Criaremos a variável registerForm
do tipo FormGroup
. No método ngOnInit
, estabeleceremos os controles para o formulário usando a classe FormBuilder
. Todos os campos são definidos como um campo obrigatório para este formulário. Chamaremos o método userNameValidator
do serviço usando a função bind
.
Para o campo de senha, usaremos o método de composição para mesclar em vários validadores em uma única função. Também invocaremos o método MatchPassword
e passaremos o nome de password
e confirmPassword
como parâmetros.
A propriedade registerFormControl
retornará os controles de formulário. O método onSubmit
imprimirá o conteúdo do formulário no console se o formulário for válido e enviado com sucesso.
Agora, abra reactive-form.component.html
e cole nele o código a seguir:
<div class="container">
<div class="row">
<div class="col-md-8 mx-auto">
<div class="card">
<div class="card-header">
<h3>Angular Reactive Form</h3>
</div>
<div class="card-body">
<form class="form" [formGroup]="registerForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" formControlName="name">
<span class="text-danger"
*ngIf="(registerFormControl.name.touched || submitted) && registerFormControl.name.errors?.required">
Name is required
</span>
</div>
<div class="form-group">
<label>Email</label>
<input type="text" class="form-control" formControlName="email">
<span class="text-danger"
*ngIf="(registerFormControl.email.touched || submitted) && registerFormControl.email.errors?.required">
Email is required
</span>
<span class="text-danger"
*ngIf="registerFormControl.email.touched && registerFormControl.email.errors?.email">
Enter a valid email address
</span>
</div>
<div class="form-group">
<label>User Name</label>
<input type="text" class="form-control" formControlName="username">
<span class="text-danger"
*ngIf="(registerFormControl.username.touched || submitted) && registerFormControl.username.errors?.required">
User Name is required
</span>
<span class="text-danger"
*ngIf="registerFormControl.username.touched && registerFormControl.username.errors?.userNameNotAvailable">
User Name is not available
</span>
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" formControlName="password">
<span class="text-danger"
*ngIf="(registerFormControl.password.touched || submitted) && registerFormControl.password.errors?.required">
Password is required
</span>
<span class="text-danger"
*ngIf="registerFormControl.password.touched && registerFormControl.password.errors?.invalidPassword">
Password should have minimum 8 characters, at least 1 uppercase letter, 1 lowercase
letter and 1 number
</span>
</div>
<div class="form-group">
<label>Confirm Password</label>
<input type="password" class="form-control" formControlName="confirmPassword">
<span class="text-danger"
*ngIf="(registerFormControl.confirmPassword.touched || submitted)&& registerFormControl.confirmPassword.errors?.required">
Confirm Password is required
</span>
<span class="text-danger"
*ngIf="registerFormControl.confirmPassword.touched && registerFormControl.confirmPassword.errors?.passwordMismatch">
Passwords doesnot match
</span>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Register</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
Criaremos um reactive-form e usaremos o card do Bootstrap para a estilização. O cabeçalho do nosso card terá um título, enquanto o corpo terá os campos do formulário. Vincularemos a propriedade formGroup
da tag <form>
ao nome do nosso formulário, que é registerForm
. O método onSubmit
será invocado ao enviar o formulário. Também vincularemos a propriedade formControlName
de cada campo de entrada ao nome de controle do nosso FormGroup
. Verificaremos se há erros nos controles do formulário e, em seguida, exibiremos a mensagem de erro de validação apropriada na tela.
Execute o seguinte comando para criar o componente nav-bar:
ng g c nav-bar
Abra nav-bar.component.html
e cole o código abaixo:
<nav class="navbar navbar-expand-sm navbar-dark bg-dark fixed-top">
<a class="navbar-brand" [routerLink]='["/"]'>Form Validation Demo</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" [routerLink]='["/reactive-form"]'>Reactive Form</a>
</li>
</ul>
</div>
</nav>
Estamos adicionando o link de navegação ao componente da reactive-form na barra de navegação.
Atualizando o componente do aplicação
Abra o arquivo app.component.html
e cole nele o código abaixo:
<app-nav-bar></app-nav-bar>
<div class="container">
<router-outlet></router-outlet>
</div>
Atualizando o módulo da aplicação
Adicione o código a seguir no arquivo app.module.ts
. Vamos importar o módulo de formulários e definir o roteamento para nossa aplicação. Você pode consultar GitHub para obter o código-fonte completo deste arquivo.
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
...
imports: [
...
ReactiveFormsModule,
RouterModule.forRoot([
{ path: '', component: ReactiveFormComponent },
{ path: 'reactive-form', component: ReactiveFormComponent }
]),
],
})
Demonstração da execução
Usaremos o comando abaixo para iniciar o servidor:
ng serve -o
Este comando iniciará a aplicação no seu navegador. Caso não abra automaticamente, você pode digitar http://localhost:4200/
na barra do seu navegador. Você pode realizar todas as validações de formulário que vimos aqui.
Esta aplicação também está hospedada em https://ng-forms-validation.herokuapp.com/. Navegue até o link e faça alguns testes para uma melhor compreensão.
Resumo
Criamos um modelo de formulário de registro de usuário utilizando a abordagem reactive-form no Angular. Também implementamos as validações integradas e personalizadas no formulário. Por fim, utilizamos a biblioteca do Bootstrap para a estilização.
Você pode obter o código-fonte no GitHub e fazer alguns testes para uma melhor compreensão.
Você pode encontrar outras publicações como esta no blog do autor, Ankit Sharma (em inglês).