Olá mundo!
O objetivo deste artigo é criar uma página para visualização das informações dos clientes já cadastrados. Com isso, vamos conhecer o componente thf-page-detail
e alguns componentes para exibição de dados.
Pré-requisitos
Não deixe de ler os artigos anteriores para ter uma compreensão mais completa do projeto e acompanhar a evolução passo a passo.
Caso tenha perdido as primeiras partes desta série, não deixe de conferir:
- Criando um CRUD com THF – Parte 01: iniciando o projeto
- Criando um CRUD com THF – Parte 02: listando nossos clientes
- Criando um CRUD com THF – Parte 03: pesquisando pelos nossos clientes
- Criando um CRUD com THF – Parte 04: criando um novo cliente
Para continuar do ponto anterior, basta clonar o projeto com o que já foi implementado.
git clone --branch post-4 https://github.com/jhosefmarks/sample-thf-crud-customers.git <sua-pasta-de-trabalho>
Passo 1 – Iniciando nossa página de visualização
Começaremos criando o componente da nossa nova página.
ng g c customers/customer-view
Uma nova pasta será criada: src/app/customers/customer-view. Dentro dela, os seguintes arquivos também deverão ter sido criados após o comando:
- customer-view.component.css
- customer-view.component.html
- customer-view.component.spec.ts
- customer-view.component.ts
Além da nova pasta e dos novos arquivos, o arquivo src/app/customers/customers.module.ts também foi atualizado, adicionando o novo componente dentro do módulo:
Configurando uma nova rota
Abra o arquivo customers-routing.module.ts e inclua a rota para visualização dos dados do nosso cliente:
Configuração da nova rota
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { CustomerFormComponent } from './customer-form/customer-form.component';
import { CustomerListComponent } from './customer-list/customer-list.component';
// NOVO IMPORT
import { CustomerViewComponent } from './customer-view/customer-view.component';
const routes: Routes = [
{ path: '', component: CustomerListComponent },
{ path: 'new', component: CustomerFormComponent },
// NOVA ROTA
{ path: 'view/:id', component: CustomerViewComponent }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class CustomersRoutingModule { }
Observe que nessa nova rota estamos usando um parâmetro chamado “id”. Já que vamos visualizar os dados de um cliente já cadastrado, precisamos dessa informação para buscar no back-end os dados necessários para nossa página.
Já fizemos algo parecido no segundo e terceiro artigo, então você já deve saber que isso ainda não é suficiente para vermos algum resultado visual. Portanto, abra o arquivo customer-view.component.html e insira o componente thf-page-detail:
Configuração inicial do thf-page-detail
<thf-page-detail
t-title="Detalhes do cliente">
</thf-page-detail>
Com isso, já podemos acessar nossa nova página através da url:
Esse id 0148093543698 está em nossa base de teste, mas pode ser outro id de acordo com seu exemplo.
Passo 2 – Abrindo a página de detalhes a partir da página de listagem
Vai ficar muito complicado se a gente ficar testando nossa página sem ter um id real em nossa base de teste – isso pode limitar nossos testes, então vamos voltar na nossa página de listagem e, a partir de lá, vamos abrir nossa página de visualização.
Assim, não vamos precisar nos preocupar em informar um id válido na url – inclusive, vamos poder visualizar um cliente cadastrado em nossos testes durante o desenvolvimento.
Vamos acessar o arquivo customer-list.component.ts, incluir uma lista de ações para nossa tabela e criar uma função para navegar para nossa página de detalhes, passando o id do cliente em nossa url.
Atualização do customer-list.component.ts
...
// NOVO IMPORT
import { ThfTableAction, ThfTableColumn } from '@totvs/thf-ui/components/thf-table';
...
export class CustomerListComponent implements OnInit, OnDestroy {
...
// NOVA LISTA DE AÇÕES PARA O TABLE
public readonly tableActions: Array<ThfTableAction> = [
{ action: this.onViewCustomer.bind(this), label: 'Visualizar' }
];
...
constructor(private httpClient: HttpClient) { }
...
// NOVA FUNÇÃO PRA NAVEGAR ATÉ A PÁGINA DE DETALHES
private onViewCustomer(customer) {
this.router.navigateByUrl(`/customers/view/${customer.id}`);
}
...
}
Agora vamos associar a propriedade tableActions na nossa tabela:
Página customer-list.component.html atualizada
<thf-page-list ...>
<!-- PROPRIEDADE T-ACTIONS CONFIGURADA -->
<thf-table
[t-actions]="tableActions"
... >
</thf-table>
</thf-page-list>
...
Com isso, teremos o seguinte resultado:
Passo 3 – Buscando os dados do back-end para serem exibidos
Com a navegação pronta e a garantia de que o id passado vai nos retornar dados “reais” para exibição, vamos pegar o id da url (rota) e vamos fazer a chamada para o back-end buscando os dados que deverão ser exibidos.
Vamos voltar para o nosso arquivo customer-view.component.ts e faremos as alterações necessárias.
Buscando os dados do back-end
import { Component, OnDestroy, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-customer-view',
templateUrl: './customer-view.component.html',
styleUrls: ['./customer-view.component.css']
})
export class CustomerViewComponent implements OnDestroy, OnInit {
// URL DA NOSSA API
private readonly url: string = 'https://sample-customers-api.herokuapp.com/api/thf-samples/v1/people';
private customerSub: Subscription;
private paramsSub: Subscription;
constructor(private httpClient: HttpClient, private route: ActivatedRoute) { }
ngOnInit() {
// APENAS PEGAMOS O ID DA ROTA ATIVA E PASSAMOS PARA NOSSA FUNÇÃO LOADDATA
this.paramsSub = this.route.params.subscribe(params => this.loadData(params['id']));
}
ngOnDestroy() {
this.paramsSub.unsubscribe();
this.customerSub.unsubscribe();
}
// FUNÇÃO QUE CARREGA OS DADOS DO CLIENTE
private loadData(id) {
this.customerSub = this.httpClient.get(`${this.url}/${id}`).subscribe(console.log);
}
}
- O arquivo todo foi reescrito nessa etapa.
Aqui apenas configuramos a chamada da API baseada no id passado na url. Notem que não fazemos nenhuma verificação se existe ou não o id, já que o mesmo é obrigatório em nossa rota para chegar na página de visualização.
Já na função loadData disparamos a requisição get do httpClient e apenas fazemos log dos dados que serão exibidos em nosso console. Com isso, já dá pra verificar se os dados realmente estão sendo recebidos.
Caso seja passado um id inválido direto para a url, você não precisa se preocupar – o THF vai exibir uma notificação para o usuário informando o problema. Ou seja, o THF trabalha por você e para você.
Para que isso funcione corretamente, seu back-end precisa devolver um 404 com as mensagens de erro no corpo da requisição.
Passo 4 – Finalmente exibindo os dados
Finalmente chegamos na parte que realmente importa: vamos mostrar os dados para o usuário.
Vamos criar uma propriedade para salvar os dados do cliente e atribuir o resultado da requisição nessa propriedade.
Armazenando a resposta da requisição
...
export class CustomerViewComponent implements OnDestroy, OnInit {
...
customer: any = {};
...
constructor(private httpClient: HttpClient, private route: ActivatedRoute) { }
...
private loadData(id) {
// PEGA A RESPOSTA DA REQUISIÇÃO E GUARDA NA PROPRIEDADE CUSTOMER
this.customerSub = this.httpClient.get(`${this.url}/${id}`)
.subscribe(response => this.customer = response);
}
}
Vamos incluir alguns componentes do tipo thf-info em nossa página.
Componente thf-info configurados na página
<thf-page-detail
t-title="Detalhes do cliente">
<!-- NOVOS COMPONENTES -->
<thf-info t-label="Nome" [t-value]="customer.name"></thf-info>
<thf-info t-label="Nascimento" [t-value]="customer.birthdate"></thf-info>
<thf-info t-label="Gênero" [t-value]="customer.genre"></thf-info>
<thf-info t-label="Status" [t-value]="customer.status"></thf-info>
</thf-page-detail>
Recarregando nossa página, teremos o seguinte resultado:
Bom, já temos algumas informações sendo exibidas. O thf-info exibe os dados verticalmente por padrão, mas podemos usar o Grid System do THF para melhorar a organização dos nossos componentes.
E para a informação referente ao status do cliente, nós podemos usar o thf-tag para dar um pouco mais de destaque.
Inclusão do Grid System e do thf-tag
<thf-page-detail
t-title="Detalhes do cliente">
<!-- INCLUSÃO DO GRID SYSTEM -->
<div class="thf-row">
<thf-info class="thf-sm-12 thf-md-6"
t-label="Nome"
[t-value]="customer.name">
</thf-info>
<thf-info class="thf-sm-12 thf-md-2"
t-label="Nascimento"
[t-value]="customer.birthdate">
</thf-info>
<thf-info class="thf-sm-12 thf-md-2"
t-label="Gênero"
[t-value]="customer.genre">
</thf-info>
<!-- TROCA DO THF-INFO PELO THF-TAG -->
<thf-tag class="thf-sm-12 thf-md-2"
t-label="Status"
[t-value]="customer.status">
</thf-tag>
</div>
</thf-page-detail>
Com isso, nossa página já começa a ficar mais organizada e bacana. Simples, mas bacana.
Agora vamos incluir as demais informações na tela e deixar nossa página com todas as informações do cliente.
Todos os thf-info configurados em nosso HTML
<thf-page-detail
t-title="Detalhes do cliente">
<div class="thf-row">
<thf-info class="thf-md-5"
t-label="Nome"
[t-value]="customer.name">
</thf-info>
<thf-info class="thf-md-5"
t-label="E-mail"
[t-value]="customer.email">
</thf-info>
<thf-tag class="thf-md-2"
t-label="Status"
[t-value]="customer.status">
</thf-tag>
</div>
<div class="thf-row">
<thf-info class="thf-md-3"
t-label="Apelido"
[t-value]="customer.nickname">
</thf-info>
<thf-info class="thf-md-3"
t-label="Nascimento"
[t-value]="customer.birthdate">
</thf-info>
<thf-info class="thf-md-3"
t-label="Gênero"
[t-value]="customer.genre">
</thf-info>
<thf-info class="thf-md-3"
t-label="Nacionalidade"
[t-value]="customer.nationality">
</thf-info>
</div>
<div class="thf-row">
<thf-info class="thf-md-5"
t-label="Nome da mãe"
[t-value]="customer.mother">
</thf-info>
<thf-info class="thf-md-5"
t-label="Nome do pai"
[t-value]="customer.father">
</thf-info>
</div>
<div class="thf-row">
<thf-info class="thf-md-6"
t-label="Rua"
[t-value]="customer.street">
</thf-info>
<thf-info class="thf-md-3"
t-label="Cidade/Estado"
[t-value]="customer.city">
</thf-info>
<thf-info class="thf-md-3"
t-label="País"
[t-value]="customer.country">
</thf-info>
</div>
</thf-page-detail>
Agora podemos ver todas as informações na tela:
Mesmo usando o Grid System, as informações parecem estar bagunçadas, apenas jogadas na página, mas podemos melhorar isso usando o thf-divider.
Assim como fizemos com a nossa página de cadastro de clientes, podemos usar o componente para criar agrupamentos que melhoram a leitura e visualização das informações.
Adição do thf-divider
<thf-page-detail
t-title="Detalhes do cliente">
<!-- ADICIONADO THF-DIVIDER -->
<thf-divider t-label="Dados pessoais"></thf-divider>
...
<thf-divider t-label="Filiação"></thf-divider>
...
<thf-divider t-label="Endereço"></thf-divider>
...
</thf-page-detail>
Passo 5 – Formatando melhor as informações
Se você notou, nós temos algumas informações que não estão sendo bem apresentadas, ou não estão da melhor forma possível – uma delas é a data de nascimento.
O thf-info permite o uso de pipes para exibição das informações. Vamos usar o DatePipe padrão do Angular para formatar a data no formato brasileiro: dia, mês e ano.
Formatando a data usando DatePipe do Angular
<thf-page-detail
t-title="Detalhes do cliente">
...
<!-- FORMATANDO A DATA USANDO O PIPEDATE -->
<thf-info class="thf-md-3"
t-label="Nascimento"
[t-value]="customer.birthdate | date:'dd/MM/yyyy'">
</thf-info>
...
</thf-page-detail>
Outros dados como status e gender têm valores padronizados e estão em inglês. Nós poderíamos usar tradução nesta página usando i18n do THF, mas não é o foco de hoje.
Teremos outros artigos só sobre isso. Agora vamos fazer apenas um map nos dados retornados pelo nosso back-end, transformando os valores para serem exibidos de forma mais elegante.
Transformação dos dados vindos do back-end usando o map do rxjs
...
// NOVO IMPORT
import { map } from 'rxjs/operators';
...
export class CustomerViewComponent implements OnDestroy, OnInit {
...
constructor(private httpClient: HttpClient, private route: ActivatedRoute) { }
...
private loadData(id) {
this.customerSub = this.httpClient.get(`${this.url}/${id}`)
// INCLUSÃO DO MAP PARA TRANSFORMAR OS DADOS
.pipe(
map((customer: any) => {
const status = { Active: 'Ativo', Inactive: 'Inativo' };
const genre = { Female: 'Feminino', Male: 'Masculino', Other: 'Outros' };
customer.status = status[customer.status];
customer.genre = genre[customer.genre];
return customer;
})
)
.subscribe(response => this.customer = response)
}
}
Com isso, teremos os dados exibidos de forma mais significativa para o usuário.
Podemos melhorar um pouco mais nossa página configurando melhor o thf-tag, que possui alguns tipos pré-definidos que podem ajudar na visualização da informação, dando mais destaque para a mesma.
Configurando do tipo da tag
<thf-page-detail
t-title="Detalhes do cliente">
...
<!-- ADICIONANDO UM TIPO PARA O THF-TAG -->
<thf-tag class="thf-md-2"
t-label="Status"
[t-type]="customer.status === 'Ativo' ? 'success' : 'danger'"
[t-value]="customer.status">
</thf-tag>
...
</thf-page-detail>
Passo 6 – Incluindo ações na página de visualização
Como no componente thf-page-edit, o thf-page-detail tem algumas ações padrão. Por enquanto vamos adicionar apenas a função de voltar em nossa página.
Para isso, basta criar uma função chamada back, e nela vamos fazer a navegação para nossa tela de listagem.
Função para retornar a página de listagem dos nossos clientes
...
// NOVO IMPORT
import { ActivatedRoute, Router } from '@angular/router';
...
export class CustomerViewComponent implements OnDestroy, OnInit {
...
constructor(private httpClient: HttpClient, private route: ActivatedRoute, private router: Router) { }
...
// NOVA FUNÇÃO
back() {
this.router.navigateByUrl('customers');
}
}
Com isso, temos nosso fluxo de navegação completo entre as páginas de listagem e visualização dos dados do cliente:
Com isso, concluímos nossa página de visualização (por enquanto, pois voltaremos nela em outro artigo).
E agora?
Com mais essa etapa completa, temos nosso CRUD quase pronto, mas ainda dá pra fazer muita coisa. Agora você já pode fazer páginas para exibir as informações cadastradas nos seus formulários e explorar outros componentes para criar layouts mais complexos.
Falta pouco agora para finalizar nosso CRUD. Nos vemos no próximo artigo.
Você pode encontrar os fontes do projeto no meu GitHub.
Referências e dicas de leitura
Documentação oficial do THF:
Documentação oficial do Angular:
learnrxjs.io:
***
Artigo original publicado no TOTVS Developers e republicado com autorização do autor, Jhosef Marks: https://medium.com/totvsdevelopers/criando-um-crud-com-thf-visualizando-dados-de-um-cliente-ea3163db2d97