Como criar formulários do tipo Reactive Forms com Angular

Reactive Forms

Reactive Forms é uma das duas maneiras de criar formulários com o Angular.
Nesse tutorial você vai aprender

  • Criar um formulário com um componente
  • Usar o formControlName para criar o two-way data bindings para ler e escrever nos inputs na tela
  • Como limpar os campos na tela após submeter o formulário

Pré-requisitos

Esse tutorial foi feito utilizando o bootstrap para criação de uma interface mais amigável. Se você não sabe o que é o bootstrap, clique aqui para ver o tutorial.

Também foi utilizada a versão 7.0 do Angular.

Passo a passo para a criação do formulário

  1. Instalação do ReactiveFormsModule
  2. Criar a classe que será o modelo do formulário
  3. Criar o componente com o formulário
  4. Aplicar o formGroup no formulário formControlName nos inputs
  5. Fazer o formulário submter

1 – Instalação do ReactiveFormsModule

Antes de começar, você precisa importar o módulo ReactiveFormsModule no seu projeto.
Esse modulo possui todas as diretivas de criação de formulários do tipo Reactive Forms. É necessário efetuar o import antes de qualquer componente que use um formulário.
Para importar, é só incluir a linha abaixo no arquivo app.module.ts.

import { ReactiveFormsModule } from '@angular/forms';

O arquivo app.module.ts deve ficar assim:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

2 – Criar a classe que será o modelo do formulário

Para esse exemplo, será criado uma classe de cliente com os campos abaixo.
Para criar uma classe é só rodar o comando abaixo.

ng g class clientes/shared/cliente

O arquivo cliente.ts deve ficar assim:

export class Cliente {
  nome: string = '';
  tipo: number = 1;
  genero: number = 1;
  dataNascimento: Date = null;
  observacao: string = '';
  inativo: boolean = false;
}

3 – Criar o componente com o formulário

O formulário no Angular é um formulário comum com a adição do formControlName para fazer o binding entre o controle na tela e o objeto de formulário que você está usando.

Criar o componente
Para criar o componente que terá o formulário, é só rodar o comando abaixo

ng g component clientes/formulario

A principio o arquivo formulario.component.html deve ficar assim:

<form>

  <div class="form-group">
    <label for="nome">Nome</label>
    <input type="text" class="form-control" name="nome" id="nome" required>
  </div>

  <div class="form-group">
    <label for="tipo">Tipo</label>
    <select class="form-control" name="tipo" id="tipo">
      <option value="1">Pessoa física</option>
      <option value="2">Pessoa jurídica</option>
    </select>
  </div>

  <div class="form-group">
    <label>Gênero</label>

    <div class="form-check">
      <input class="form-check-input" type="radio" name="genero" id="masculino" [value]="1">
      <label class="form-check-label" for="masculino">Masculino</label>
    </div>
    <div class="form-check">
      <input class="form-check-input" type="radio" name="genero" id="feminino" [value]="2">
      <label class="form-check-label" for="feminino">Feminino</label>
    </div>
  </div>

  <div class="form-group">
    <label for="dataNascimento">Data de nascimento</label>
    <input type="date" class="form-control" name="dataNascimento" id="dataNascimento">
  </div>

  <div class="form-group">
    <label for="observacao">Observação</label>
    <textarea class="form-control" rows="3" name="observacao" id="observacao"></textarea>
  </div>

  <div class="form-check">
    <input class="form-check-input" type="checkbox" name="inativo" id="inativo">
    <label class="form-check-label" for="inativo">Inativo</label>
  </div>

  <input type="submit" class="btn btn-primary mt-4" value="Salvar">
  <a href="#" class="btn btn-secondary mt-4 ml-2">Cancelar</a>

</form>

Criação do objeto de formulário
Para fazer o binding na tela, é necessário criar um objeto que será um agrupador de inputs que existiram na tela. Esse objeto é do tipo FormGroup e os inputs são do tipo FormControl. Para criar esse objeto, você pode usar diretamente os tipos mencionados acima ou usar o FormBuilder.

Exemplo 1: Usando diretamente os tipos.
É necessário fazer o import abaixo no componente

import { FormGroup, FormControl } from '@angular/forms';

Agora é necessário criar uma função para criação do objeto do formulário

createForm(cliente: Cliente) {
  this.formCliente = new FormGroup({
    nome: new FormControl(cliente.nome),
    tipo: new FormControl(cliente.tipo),
    genero: new FormControl(cliente.genero),
    dataNascimento: new FormControl(cliente.dataNascimento),
    observacao: new FormControl(cliente.observacao),
    inativo: new FormControl(cliente.inativo)
  })
}

O arquivo formulario.component.ts deve ficar assim:

import { Component, OnInit } from '@angular/core';
import { Cliente } from '../shared/cliente';
import { FormGroup, FormControl } from '@angular/forms';

@Component({
  selector: 'app-formulario',
  templateUrl: './formulario.component.html',
  styleUrls: ['./formulario.component.scss']
})
export class FormularioComponent implements OnInit {
  formCliente: FormGroup;

  constructor() { }

  ngOnInit() {
    this.createForm(new Cliente());
  }

  createForm(cliente: Cliente) {
    this.formCliente = new FormGroup({
      nome: new FormControl(cliente.nome),
      tipo: new FormControl(cliente.tipo),
      genero: new FormControl(cliente.genero),
      dataNascimento: new FormControl(cliente.dataNascimento),
      observacao: new FormControl(cliente.observacao),
      inativo: new FormControl(cliente.inativo)
    })
  }
}

Exemplo 2: Usando o FormBuilder.
É necessário fazer o import abaixo no componente

import  {  FormBuilder,  FormGroup  }  from  '@angular/forms';

No construtor do componente você receber uma instancia do objeto FormBuilder por injeção de dependencia

constructor(private formBuilder: FormBuilder) { }

Agora é necessário criar uma função para criação do objeto do formulário

createForm(cliente: Cliente) {
  this.form = this.formBuilder.group({
    nome: [cliente.nome],
    tipo: [cliente.tipo],
    genero: [cliente.genero],
    dataNascimento: [cliente.dataNascimento],
    observacao: [cliente.observacao],
    inativo: [cliente.inativo]
  })
}

O arquivo formulario.component.ts deve ficar assim:

import { Component, OnInit } from '@angular/core';
import { Cliente } from '../shared/cliente';
import { FormBuilder, FormGroup } from '@angular/forms';

@Component({
  selector: 'app-formulario',
  templateUrl: './formulario.component.html',
  styleUrls: ['./formulario.component.scss']
})
export class FormularioComponent implements OnInit {
  formCliente: FormGroup;

  constructor(private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.createForm(new Cliente());
  }

  createForm(cliente: Cliente) {
    this.formCliente = this.formBuilder.group({
      nome: [cliente.nome],
      tipo: [cliente.tipo],
      genero: [cliente.genero],
      dataNascimento: [cliente.dataNascimento],
      observacao: [cliente.observacao],
      inativo: [cliente.inativo]
    })
  }
}

Exibir o formulário na tela
Para ver o resultado na tela, é necessário incluir o componente de formulário no componente raiz da aplicação app.component.
O arquivo app.component.html deve ficar assim:

<app-formulario></app-formulario>

4 – Aplicar o formGroup no formulário formControlName nos inputs

Primeiro é necessário fazer o binding do tag form com o objeto de formulário criado.
Para isso é só adicionar a diretiva [formGroup] na tag form com o valor do nome do objeto criado para o formulário.
No exemplo acima foi criado um objeto de nome “formCliente”, logo ele será o valor do [formGroup].

<form  [formGroup]="formCliente">

Agora é hora de usar a diretiva formControlName para poder fazer o binding dos controles.
Para isso em cada input na tela será colocado o formControlName.
O arquivo formulario.component.html deve ficar assim:

<form [formGroup]="formCliente">

  <div class="form-group">
    <label for="nome">Nome</label>
    <input type="text" class="form-control" name="name" id="nome" formControlName="nome">
  </div>

  <div class="form-group">
    <label for="tipo">Tipo</label>
    <select class="form-control" name="tipo" id="tipo" formControlName="tipo">
      <option value="1">Pessoa física</option>
      <option value="2">Pessoa jurídica</option>
    </select>
  </div>

  <div class="form-group">
    <label>Gênero</label>

    <div class="form-check">
      <input class="form-check-input" type="radio" name="genero" id="masculino" [value]="1" formControlName="genero">
      <label class="form-check-label" for="masculino">Masculino</label>
    </div>
    <div class="form-check">
      <input class="form-check-input" type="radio" name="genero" id="feminino" [value]="2" formControlName="genero">
      <label class="form-check-label" for="feminino">Feminino</label>
    </div>
  </div>

  <div class="form-group">
    <label for="dataNascimento">Data de nascimento</label>
    <input type="date" class="form-control" name="dataNascimento" id="dataNascimento" formControlName="dataNascimento">
  </div>

  <div class="form-group">
    <label for="observacao">Observação</label>
    <textarea class="form-control" rows="3" name="observacao" id="observacao" formControlName="observacao"></textarea>
  </div>

  <div class="form-check">
    <input class="form-check-input" type="checkbox" name="inativo" id="inativo" formControlName="inativo">
    <label class="form-check-label" for="inativo">Inativo</label>
  </div>

  <input type="submit" class="btn btn-primary mt-4" value="Salvar">
  <a href="#" class="btn btn-secondary mt-4 ml-2">Cancelar</a>

</form>

Com isso todo valor que você digitar na tela será salvo na respectiva propriedade do objeto “formCliente” e todo valor que você colocar em alguma propriedade do “formCliente” será exibido na tela.
Um exemplo disso é mostrado no vídeo acima.

5 – Fazer o formulário submter

Para fazer o formulário submeter é necessário criar um método no arquivo formulario.component.ts e adicionar a chamada desse método no evento (ngSubmit) do formulário.

Método para submeter o formulário

onSubmit() {
  // aqui você pode implementar a logica para fazer seu formulário salvar
  console.log(this.formCliente.value);
}

E na tag form adicionar

(ngSubmit)="onSubmit()"

Limpando os campos do formulário
Para limpar os valores preenchidos na tela de maneira você tem duas opções.

Opção 1: Chamar novamente a função createForm com um novo objeto de cliente.

onSubmit() {
  // aqui você pode implementar a logica para fazer seu formulário salvar
  console.log(this.formCliente.value);

  // chamando a função createForm para limpar os campos na tela
  this.createForm(new Cliente());
}

Opção 2: Usar o método reset do formCliente

onSubmit() {
    // aqui você pode implementar a logica para fazer seu formulário salvar
    console.log(this.cliente);
    // Usar o método reset para limpar os controles na tela
    this.formCliente.reset(new  Cliente());
  }

O exemplo completo do arquivos formulario.component.ts e formulario.component.html está abaixo:

Arquivo formulario.component.ts

import { Component, OnInit } from '@angular/core';
import { Cliente } from '../shared/cliente';
import { FormBuilder, FormGroup } from '@angular/forms';

@Component({
  selector: 'app-formulario',
  templateUrl: './formulario.component.html',
  styleUrls: ['./formulario.component.scss']
})
export class FormularioComponent implements OnInit {
  formCliente: FormGroup;

  constructor(private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.createForm(new Cliente());
  }

  createForm(cliente: Cliente) {
    this.formCliente = this.formBuilder.group({
      nome: [cliente.nome],
      tipo: [cliente.tipo],
      genero: [cliente.genero],
      dataNascimento: [cliente.dataNascimento],
      observacao: [cliente.observacao],
      inativo: [cliente.inativo]
    })
  }

  onSubmit() {
    // aqui você pode implementar a logica para fazer seu formulário salvar
    console.log(this.formCliente.value);

    // Usar o método reset para limpar os controles na tela
    this.formCliente.reset(new Cliente());
  }
}

Arquivo formulario.component.html

<form [formGroup]="formCliente" (ngSubmit)="onSubmit()">

  <div class="form-group">
    <label for="nome">Nome</label>
    <input type="text" class="form-control" name="name" id="nome" formControlName="nome">
  </div>

  <div class="form-group">
    <label for="tipo">Tipo</label>
    <select class="form-control" name="tipo" id="tipo" formControlName="tipo">
      <option value="1">Pessoa física</option>
      <option value="2">Pessoa jurídica</option>
    </select>
  </div>

  <div class="form-group">
    <label>Gênero</label>

    <div class="form-check">
      <input class="form-check-input" type="radio" name="genero" id="masculino" [value]="1" formControlName="genero">
      <label class="form-check-label" for="masculino">Masculino</label>
    </div>
    <div class="form-check">
      <input class="form-check-input" type="radio" name="genero" id="feminino" [value]="2" formControlName="genero">
      <label class="form-check-label" for="feminino">Feminino</label>
    </div>
  </div>

  <div class="form-group">
    <label for="dataNascimento">Data de nascimento</label>
    <input type="date" class="form-control" name="dataNascimento" id="dataNascimento" formControlName="dataNascimento">
  </div>

  <div class="form-group">
    <label for="observacao">Observação</label>
    <textarea class="form-control" rows="3" name="observacao" id="observacao" formControlName="observacao"></textarea>
  </div>

  <div class="form-check">
    <input class="form-check-input" type="checkbox" name="inativo" id="inativo" formControlName="inativo">
    <label class="form-check-label" for="inativo">Inativo</label>
  </div>

  <input type="submit" class="btn btn-primary mt-4" value="Salvar">
  <a href="#" class="btn btn-secondary mt-4 ml-2">Cancelar</a>

</form>

Referências