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:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#
Super DVD C# - Recursos de aprendizagens e vídeo aulas para C#
Curso Fundamentos da Programação Orientada a Objetos com VB .NET
NET - Criando um livro de contatos usando o AngularJS - Macoratti
NET - AngularJS : Apresentação (início do curso) - Macoratti
ASP .NET MVC - Crud com Entity Framework e AngularJS - Macoratti
AngularJS - Conceitos Básicos - YouTube (série de 13 vídeo aulas sobre o Angular)
NET - O que é TypeScript e quais os seus benefícios - Macoratti
TypeScript - Configurando o VS Community 2015 para ... - Macoratti
Visual Studio - Bem-Vindo Node.js : desenvolvendo para Node.js na plataforma .NET