Angular 2 - Cadastro de Clientes - XX (final)


 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 vamos implementar a mensagem para informar ao usuário se o cliente foi excluído ou não com sucesso e assim concluir o nosso projeto. (link do artigo anterior)

A exclusão de um cliente é feita clicando no botão Deletar do respectivo cliente na lista de clientes.

Quando o usuário clicar no botão Deletar é recomendado que seja emitida uma solicitação de confirmação para excluir o cliente.

Para isso vamos criar um serviço no Angular2 que vai usar o confirm nativo do JavaScript através de uma Promise.

Nota: O método confirm() exibe uma caixa de diálogo com uma mensagem especificada, juntamente com um botão OK e Cancelar

Criando um Service para confirmar a exclusão do cliente

Vamos criar na pasta app do projeto o arquivo dialogconfirm.service.ts e definir o código abaixo nestse arquivo:

import { Injectable } from '@angular/core';
@Injectable()
export class DialogConfirmService {
    confirm(message? : string) 
    {
        return new Promise(resolve => {
            return resolve(window.confirm(message || 'Confirma ?'));
        });
    }
}

Vamos entender o código criado:

Definimos a classe DialogConfirmService contendo método confirm que pode ou não receber uma mensagem.

A seguir definimos uma nova Promise e usamos o resolve para retornar a resolução da promise com o valor que será o retorno do confirm que será a mensagem ou se não for passada a mensagem será exibido o texto Confirma ?.

E é só isso. O serviço esta pronto para ser usado. Vamos agora criar o método para deletar o cliente.

Criando o método para deletar o cliente

Para deletar um cliente vamos criar um novo método chamado delete() no arquivo cliente.service.ts no VS Code.

Abra o arquivo cliente.service.ts e inclua o código destacado em azul:

import { Injectable } from '@angular/core';
import { Http, Headers, Response } from '@angular/http';
import 'rxjs/add/operator/toPromise';
import { Cliente } from './cliente.model';
import { CLIENTES } from './clientes-mock';
@Injectable()
export class ClienteService{
   // app é a pasta de onde fizermos a chamada
   // clientes é o nome da variável na classe InMemoryDataService
   private clientesUrl : string = 'app/clientes';
   private headers: Headers = new Headers ({'Content-Type' : 'application/json'})
    constructor(
       private http: Http
    ) {}
    getClientes() : Promise<Cliente[]> {
       return this.http.get(this.clientesUrl) 
         .toPromise()
         .then(response => response.json().data as Cliente[])
         .catch(this.trataErro);
      }
    private trataErro(err : any) : Promise<any> {
        return Promise.reject(err.message || err );
      }
    getCliente(id:number): Promise<Cliente> {
           return this.getClientes()
           .then((clientes: Cliente[]) => clientes.find(cliente => cliente.id === id)); 
          }
    create(cliente: Cliente): Promise<Cliente> {
        return this.http
        .post(this.clientesUrl, JSON.stringify(cliente), {headers:this.headers})
        .toPromise()
        .then((response : Response) => {
            console.log(response.json().data);
            return response.json().data as Cliente;  
        })
        .catch(this.trataErro);
    }
     update(cliente: Cliente): Promise<Cliente> {
        const url = `${this.clientesUrl}/${cliente.id}`; //app/cliente/:id
        return this.http
        .put(url, JSON.stringify(cliente), {headers:this.headers})
        .toPromise()
        .then(() => cliente as Cliente)  
        .catch(this.trataErro);
    }
     delete(cliente: Cliente): Promise<Cliente> {
        const url = `${this.clientesUrl}/${cliente.id}`; //app/cliente/:id
        return this.http
        .delete(url, {headers:this.headers})
        .toPromise()
        .then(() => cliente as Cliente)  
        .catch(this.trataErro);
    }
}

O método delete é muito parecido com o método update.

Neste método temos :

- O método delete recebe um cliente como parâmetro e retorna uma Promise de Cliente (Promise<Cliente>)
- definimos a constante url onde definimos a url para alterar o cliente contendo o id do cliente selecionado para exclusão:
- definimos o método delete para deletar um cliente : (return this.http.delete())
- definimos a url para onde vamos enviar o post : clientesUrl ;
- definimos o cabeçalho da requisição: { headers : this.headers } ;
- Convertemos para um Promise pois o post returna um Observable : .toPromise
- Recebemos a resposta definindo .then onde usamos a classe response para retornar os dados :
cliente as Cliente;
- Usamos o nosso tratamento de erro definido na aula anterior para capturar erros: .catch(this.trataErro)

Feito isso vamos abrir o arquivo clientes-lista.component.html e definir um evento Click no botão Deletar que é criado em cada linha da tabela para exibir o cliente.

Nota: Por uma falha minha o nome clientes-lista.component.html não esta aderente ao style guide do Angular o correto seria clientes.lista.component.html (vou deixar assim, mas fica o aviso)

Altere o código do arquivo incluindo a linha em azul conforme mostrado a seguir:

<div class="container">
   <div class="row">
      <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
          <a routerLink="/cliente/salvar" class="btn btn-success">Novo</a>
          <table class="table table-striped table-hover">   
              <thead>
                  <tr>
                    <th>Nome</th>
                    <th>Email</th>
                    <th>Telefone</th>
                    <th>Deletar</th>
                  </tr>
              </thead>
              <tbody>  
                <tr *ngFor = "let c of clientes" [routerLink]= "['/cliente/salvar',c.id]">
                    <td>{{c.nome}}</td>
                    <td>{{c.email}}</td>
                    <td>{{c.telefone}}</td>
                    <td><button class="btn btn-danger" (click)="onDelete(c)">Deletar</button></td>
                </tr>
              </tbody>
          </table>
      </div>
   </div>
</div>

Definimos o método onDelete(c) no evento Click do botão Deletar passando o cliente que esta sendo selecionado na lista de clientes.

Feito isso, se você clicar no botão Deletar vai notar que seremos redirecionados para a tela de alteração de dados. Por que isso esta acontecendo ?

Vejamo o código onde definimos o evento Click:

 <tr *ngFor = "let c of clientes" [routerLink]= "['/cliente/salvar',c.id]">
                    <td>{{c.nome}}</td>
                    <td>{{c.email}}</td>
                    <td>{{c.telefone}}</td>
                    <td><button class="btn btn-danger"
(click)="onDelete(c)">Deletar</button></td>
</tr>

Perceba que no tr temos um [routerlink] que nos redireciona para a tela de alteração do cliente passando o id do cliente.

Como o Button esta contido dentro do tr, ele é um elemento filho do tr, quando clicamos no botão ele vai propagar o evento de Click para o tr também. Seria como se estivessemos clicando no tr de forma indireta. Assim o método onDelete() é executado mas o [routerlink] também é acionado.

Para evitar isso vamos incluir uma segunda instrução no evento de Click do botão usando a variável $event, que neste contexto, vai conter atributos e métodos somente do evento Click do DOM. Assim vamos definir o método stopPropagation() de forma que quando o usuário clicar no botão o evento de Click não será propagado para o tr e o [routerlink] não será acionado.

Com base nisso altere o código do arquivo clientes-lista.component.html conforme abaixo:

<div class="container">
   <div class="row">
      <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
          <a routerLink="/cliente/salvar" class="btn btn-success">Novo</a>
          <table class="table table-striped table-hover">   
              <thead>
                  <tr>
                    <th>Nome</th>
                    <th>Email</th>
                    <th>Telefone</th>
                    <th>Deletar</th>
                  </tr>
              </thead>
              <tbody>  
                <tr *ngFor = "let c of clientes" [routerLink]= "['/cliente/salvar',c.id]">
                    <td>{{c.nome}}</td>
                    <td>{{c.email}}</td>
                    <td>{{c.telefone}}</td>
                    <td><button class="btn btn-danger" (click)="onDelete(c); $event.stopPropagation()">Deletar</button></td>
                </tr>
              </tbody>
          </table>
      </div>
   </div>
</div>

Agora vamos implementar o método onDelete(c) no arquivo  clientes-lista.component.ts como mostrado a seguir:

import { DialogConfirmService } from './../dialogconfirm.service';
import {Component, OnInit} from '@angular/core';
import { Cliente } from './cliente.model';
import { ClienteService} from './cliente.service';
@Component({
    moduleId: module.id,
    selector : 'clientes-lista',
    templateUrl: 'clientes-lista.component.html'
})
export class ClientesListaComponent implements OnInit {
       clientes : Cliente[] ;
    constructor(
        private clienteService : ClienteService,
        private dialogconfirmService :  DialogConfirmService
        ){}
    ngOnInit() : void {
        this.clienteService.getClientes()
        .then((clientes : Cliente[]) => {
            this.clientes = clientes;
        }).catch(err => console.log(err));
     }
     onDelete(cliente : Cliente) : void {
        this.dialogconfirmService.confirm('Deseja excluir o cliente ' + cliente.nome + ' ?')
        .then((podeDeletar : boolean) => {
            if(podeDeletar) {
                this.clienteService
                .delete(cliente)
                .then(()=> {
                     this.clientes = this.clientes.filter((c:Cliente) => c.id != cliente.id);
                }).catch(err => {
                   console.log(err);
                });
            }
        });
     }
}

No código acima importamos o serviço e definimos uma instância do serviço no construtor da classe DialogConfirmService.

A seguir definimos o método onDelete() que recebe um cliente a ser excluido e usa o serviço para exibir a mensagem 'Deseja excluir o cliente nome_cliente' ao usuário.

Definimos uma variável boolean chamada podeDeletar e se o usuário confirmar a exclusão iremos chamar o método delete da classe ClienteService passando o cliente a ser deletado.

Estamos filtrando para exibir na lista dos clientes somente os clientes cujo id são diferentes do id do cliente que estamos deletando: this.clientes = this.clientes.filter((c:Cliente) => c.id != cliente.id);

Para concluir temos que tornar o serviço disponível no arquivo app.module.ts incluind o import para o serviço e definindo um provider para o serviço conforme o código abaixo:

import { DialogConfirmService } from './dialogconfirm.service';
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService } from './in-memory-data.service';
import { AppComponent } from './app.component';
import { AppRoutingModule} from './app-routing.module';
import { ClientesModule } from './clientes/clientes.module';
@NgModule({
    imports : [AppRoutingModule, 
               BrowserModule, 
               ClientesModule, 
               HttpModule, 
               InMemoryWebApiModule.forRoot(InMemoryDataService) 
               ],
    declarations :[AppComponent],
    providers : [
        DialogConfirmService
    ],
    bootstrap: [AppComponent]
})
export class AppModule {}

Tudo pronto. Vamos testar.

1- Abrindo nossa aplicação na lista de clientes temos a página abaixo sendo exibida:

2- Clicando no botão Deletar para a cliente Suzana Ribeiro veremos o diálogo solicitando a confirmação.

3- Clicando no botão OK teremos a lista sendo exibida novamente sem o cliente que foi deletado. No console temos a mensagem exibindo o cliente que foi deletado.

Nota: Você pode descomentar a linha para exibir os dados no console.

Lembre-se que estamos usando um API simulada e se você dar um refresh na página os dados serão perdidos pois estão apenas na memória.

E assim temos nossa aplicação com as funcionalidades para incluir, alterar e excluir implementadas. 

A aplicação pode ser melhorada em diversos aspectos e com muitas funcionalidades que não foram implementadas.

O objetivo foi mostrar como usar os principais recursos do Angular 2 criando uma aplicação básica, sem usar o Angular CLI, que pode automatizar muitas das nossas tarefas poupando-nos de muito trabalho.

Pegue o código da aplicação aqui :  cadastro_clientes_final.zip (sem a pasta ng_modules)

"Porque a lei foi dada por Moisés; a graça e a verdade vieram por Jesus Cristo." João 1:17

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