Angular 2 - Cadastro de Clientes - XIV


 Neste artigo vou mostrar como criar um cadastro de clientes e fazer o CRUD usando o Angular 2 e o Visual Studio Code.

Neste artigo vou continuar com a validação mostrando as mensagens de erro usando BootStrap e ngClass.  (link do artigo anterior)

Neste momento vamos usar os recursos do BootStrap para exibir mensagens ao usuário.

Veja a documentação da validação de formulários neste link: https://v4-alpha.getbootstrap.com/components/forms/#validation  (estou usando a versão 4)

Tomando um exemplo da documentação:

<div class="form-group has-success">
  <label class="form-control-label" for="inputSuccess1">Input with success</label>
  <input type="text" class="form-control form-control-success" id="inputSuccess1">
  <div class="form-control-feedback">Success! You've done it.</div>
  <small class="form-text text-muted">Example help text that remains unchanged.</small>
</div>

Vemos que o Bootstrap aplica uma classe ao div container do form-group, ao <Label> e ao <input type>. Vamos usar esses recursos em nosso formulário.

No Angular 2 os dois objetos fundamentais do formulário são :

Para iniciar vamos remover o estilo definido no arquivo cliente-detalhe.component.ts.

Abra este arquivo e remova o código definido para o estilo conforme abaixo:

 styles: [`
        .ng-valid[required] {
            border: 2px solid blue;
        }
        .ng-invalid:not(form) {
            border: 2px solid red;
        }
    `]

Após isso, o código deste arquivo deverá ficar assim:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params} from '@angular/router';
import { Location } from '@angular/common';
import { Cliente } from './cliente.model';
import { ClienteService } from './cliente.service';
@Component({
    moduleId: module.id,
    selector : 'cliente-detalhe',
    templateUrl : 'cliente-detalhe.component.html',
})
export class ClienteDetalheComponent implements OnInit  {
      cliente : Cliente;
      constructor(
         private clienteService : ClienteService,
         private route : ActivatedRoute,
         private location : Location
      ) {}
       ngOnInit(): void {
           this.cliente = new Cliente(0,'','','',);
           this.route.params.forEach((params: Params)=>{
               let id: number = +params['id'];
          if(id){
           this.clienteService.getCliente(id)
               .then((cliente: Cliente)=> {
                    console.log(cliente);
                    this.cliente = cliente;
               });
          }
        });
    }
}

Vamos agora abrir o template html e aplicar os recursos do bootstrap de forma estática apenas no campo nome para vermos como funciona.

Abra o arquivo cliente-detalhe.component.html e inclua o código destacado em azul:

<div class="container"> 
<h2>Salvar Cliente</h2>
<form #clienteForm="ngForm">
    <div class="form-group has-danger">
        <label for="nome" class="form-control-label">Nome</label>
        <input type="text" class="form-control form-control-danger" placeholder="Informe o nome"  
         required
         name="nome"
         [(ngModel)]="cliente.nome" >
         <div class="form-control-feedback">O campo deve ser informado</div>
    </div>
    <div class="form-group">
        <label for="email">Email</label>
        <input type="email" class="form-control" placeholder="Informe o email"         
         required
         name="email"
         [(ngModel)]="cliente.email" >
    </div>
    <div class="form-group">
        <label for="telefone">Telefone</label>
        <input type="text" class="form-control" placeholder="Informe o telefone" 
         required
         name="telefone"
         [(ngModel)]="cliente.telefone"  >
    </div>
    <button type="submit" class="btn btn-success" [disabled]="!clienteForm.form.valid">Salvar</button>
     <a class="btn btn-secondary" routerLink="/">Voltar </a>
</form>
</div>

Ao salvar as alterações veremos o resultado no navegador conforme abaixo:

Como podemos ver, os estilos do boostrap aplicados de forma estática funcionam bem, mas imagine fazer esse trabalho para um formulário com muitos campos...

É aqui que entram a diretiva ngClass e o NgModel do Angular. A diretiva ngClass adiciona e remove classes CSS a um elemento HTML.

As classes CSS são atualizadas conforme abaixo, dependendo do tipo de expressão de avaliação :

Já através a diretiva NgModel nos dá acesso aos controles dos campos do formulário. Ela deve ser aplicada na definição do campo, ou seja, no input type.

Nota: Lembre que ngModel não atua apenas fazendo o databinding mas ela atua sobre as classes CSS dos campos dos formulários.

Vamos então aplicar a diretiva ngClass e o NgModel ao nosso template html para exibir mensagens de validação de forma dinâmica.

Abra o arquivo cliente-detalhe.component.html e inclua o código destacado em azul:

<div class="container"> 
<h2>Salvar Cliente</h2>
<form #clienteForm="ngForm">
    <div [ngClass]="{'form-group': true, 'has-danger': (!nome.valid && !nome.pristine) , 'has-success': (nome.valid && !nome.pristine)}">
        <label for="nome" class="form-control-label">Nome</label>
        <input type="text" class="form-control form-control-danger" placeholder="Informe o nome"  
         required
         #nome="ngModel"
         name="nome"
         [(ngModel)]="cliente.nome" >
         <div class="form-control-feedback" [hidden]="nome.valid || nome.pristine">O campo deve ser informado</div>
    </div>
    <div class="form-group">
        <label for="email">Email</label>
        <input type="email" class="form-control" placeholder="Informe o email"         
         required
         name="email"
         [(ngModel)]="cliente.email" >
    </div>
    <div class="form-group">
        <label for="telefone">Telefone</label>
        <input type="text" class="form-control" placeholder="Informe o telefone" 
         required
         name="telefone"
         [(ngModel)]="cliente.telefone"  >
    </div>
    <button type="submit" class="btn btn-success" [disabled]="!clienteForm.form.valid">Salvar</button>
     <a class="btn btn-secondary" routerLink="/">Voltar </a>
</form>
</div>

Vamos entender o código:

- #nome="ngModel" : No input type, definimos o NgModel atribuindo-o a uma variável nome, que é o nome do campo, e assim teremos acesso a todos os controles deste campo;

- [hidden]="nome.valid || nome.pristine : Aqui vamos ocultar a mensagem de campo obrigatório quando o campo nome for válido e quando o campo não sofreu nenhuma alteração;

- [ngClass]="{'form-group': true, 'has-danger': (!nome.valid && !nome.pristine) , 'has-success': (nome.valid && !nome.pristine)

Neste código definimos o ngClass usando a notação property binding [ngClass] pois a seguir vamos usar uma expressão Javascript onde vamos definir quais classes de estilo vamos aplicar ao elemento.

Dessa forma aplicamos as seguintes classes :

  1. form-group - sempre vai ser aplicado ao container então é true; 'form-group': true
  2. has-danger - será aplicado quando o nome não for válido e o nome já tiver sido alterado;  'has-danger': (!nome.valid && !nome.pristine)
  3. has-success - será aplicado quando o nome for válido e o nome já tiver sido alterado : 'has-success': (nome.valid && !nome.pristine)

Abaixo vemos o formulário em dois momentos:

  1. Quando digitamos um caractere no campo nome
  2. Quando apagamos o caractere digitado

Vemos assim a aplicação dos estilos CSS de forma dinâmica e podemos melhorar ainda mais criando uma classe que vai permitir remover o código do template html e que vai retornar objetos que configuram as classes de estilos que vamos usar.

Abra o arquivo cliente-detalhe.component.ts e inclua o código abaixo em azul :

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params} from '@angular/router';
import { Location } from '@angular/common';
import { Cliente } from './cliente.model';
import { ClienteService } from './cliente.service';
@Component({
    moduleId: module.id,
    selector : 'cliente-detalhe',
    templateUrl : 'cliente-detalhe.component.html',
    styles: [`
        .ng-valid[required] {
            border: 2px solid blue;
        }
        .ng-invalid:not(form) {
            border: 2px solid red;
        }
    `]
})
export class ClienteDetalheComponent implements OnInit  {
      cliente : Cliente;
      constructor(
         private clienteService : ClienteService,
         private route : ActivatedRoute,
         private location : Location
      ) {}
       ngOnInit(): void {
           this.cliente = new Cliente(0,'','','',);
           this.route.params.forEach((params: Params)=>{
               let id: number = +params['id'];
          if(id){
           this.clienteService.getCliente(id)
               .then((cliente: Cliente)=> {
                    console.log(cliente);
                    this.cliente = cliente;
               });
          }
        });
    }
    getFormGroupClass(isValid : boolean, isPristine: boolean) : {} {
        return {
            'form-group' : true,
            'has-danger': !isValid && !isPristine,
            'has-success': isValid && !isPristine
        }
    }
}

Muuito bem,  agora basta aplicarmos essa classe ao template html. Abra o arquivo cliente-detalhe.component.html e defina o código destacado em azul a seguir:

<div class="container"> 
<h2>Salvar Cliente</h2>
<form #clienteForm="ngForm">
    <div [ngClass]="getFormGroupClass(nome.valid,nome.pristine)">
        <label for="nome" class="form-control-label">Nome</label>
        <input type="text" class="form-control form-control-danger" placeholder="Informe o nome"  
         required
         #nome="ngModel"
         name="nome"
         [(ngModel)]="cliente.nome" >
         <div class="form-control-feedback" [hidden]="nome.valid || nome.pristine">O campo deve ser informado</div>
    </div>
    ......
    .....
 

Você verá o formulário com o mesmo comportamento funcionando como anteriormente.

Agora vamos repetir o procedimento criando a classe para aplicar os estilos no form control e depois vamos aplicar as classes aos demais campos do formulário.

O código do arquivo cliente-detalhe.component.ts deve ficar assim:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params} from '@angular/router';
import { Location } from '@angular/common';
import { Cliente } from './cliente.model';
import { ClienteService } from './cliente.service';
@Component({
    moduleId: module.id,
    selector : 'cliente-detalhe',
    templateUrl : 'cliente-detalhe.component.html'
})
export class ClienteDetalheComponent implements OnInit  {
      cliente : Cliente;
      constructor(
         private clienteService : ClienteService,
         private route : ActivatedRoute,
         private location : Location
      ) {}
       ngOnInit(): void {
           this.cliente = new Cliente(0,'','','',);
           this.route.params.forEach((params: Params)=>{
               let id: number = +params['id'];
          if(id){
           this.clienteService.getCliente(id)
               .then((cliente: Cliente)=> {
                    console.log(cliente);
                    this.cliente = cliente;
               });
          }
        });
    }
    getFormGroupClass(isValid : boolean, isPristine: boolean) : {} {
        return {
            'form-group' : true,
            'has-danger': !isValid && !isPristine,
            'has-success': isValid && !isPristine
        };
    }
    getFormControlClass(isValid : boolean, isPristine: boolean) : {} {
        return {
            'form-control' : true,
            'has-danger': !isValid && !isPristine,
            'has-success': isValid && !isPristine
        };
    }
}

E a aplicação das classes no template html deve ficar assim: (O código alterado esta em azul)

<div class="container"> 
<h2>Salvar Cliente</h2>

<form #clienteForm="ngForm" novalidate>

    <div [ngClass]="getFormGroupClass(nome.valid,nome.pristine)">
        <label for="nome" class="form-control-label">Nome</label>
        <input type="text" placeholder="Informe o nome"  
         [ngClass]="getFormControlClass(nome.valid, nome.pristine)"
         required
         #nome="ngModel"
         name="nome"
         [(ngModel)]="cliente.nome" >
         <div class="form-control-feedback" [hidden]="nome.valid || nome.pristine">O campo nome deve ser informado</div>
    </div>
    <div [ngClass]="getFormGroupClass(email.valid, email.pristine)">
        <label for="email">Email</label>
        <input type="email" class="form-control" placeholder="Informe o email"    
         [ngClass]="getFormControlClass(email.valid, email.pristine)"     
         required
         #email="ngModel"
         name="email"
         [(ngModel)]="cliente.email" >
         <div class="form-control-feedback" [hidden]="email.valid || email.pristine">O campo email deve ser informado</div>
    </div>
    <div [ngClass]="getFormGroupClass(telefone.valid,telefone.pristine)">
        <label for="telefone">Telefone</label>
        <input type="text" class="form-control" placeholder="Informe o telefone" 
         [ngClass]="getFormControlClass(telefone.valid, telefone.pristine)"     
         required
         #telefone="ngModel"
         name="telefone"
         [(ngModel)]="cliente.telefone">
         <div class="form-control-feedback" [hidden]="telefone.valid || telefone.pristine">O campo telefone deve ser informado</div>
    </div>
    <button type="submit" class="btn btn-success" [disabled]="!clienteForm.form.valid">Salvar</button>
     <a class="btn btn-secondary" routerLink="/">Voltar </a>
</form>
</div>

E assim, concluimos a etapa da validação do formulário para nossa aplicação. Embora seja uma validação simples ela esta funcional e te da uma idéia dos recursos que o Angular oferece.

No próximo artigo vamos abordar o envio ou submit do formulário e a diretiva ngsubmit.

Pegue o código do projeto aqui : cadastro_Clientes_Angular.zip (sem a pasta node_modules)

Mas a hora vem, e agora é, em que os verdadeiros adoradores adorarão o Pai em espírito e em verdade; porque o Pai procura a tais que assim o adorem.
Deus é Espírito, e importa que os que o adoram o adorem em espírito e em verdade.

João 4:23,24

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti