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=scssEstamos 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 --saveAdicione 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\customvalidationEste 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-formAbra 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-barAbra 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 -oEste 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).