Angular
11/8/2018

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