Desenvolvimento

27 mai, 2019

Criando um CRUD com THF – Parte 05: visualizando dados de um cliente

Publicidade

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:

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
Criando componente customer-view

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:

Módulo atualizado com o componente customer-view

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.

Nova página em http://localhost:4200/customers/view/0148093543698

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:

Navegação da página de listagem para a página de detalhes.

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.

Requisição trazendo os dados do cliente e exibindo no console

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.

Exemplo de requisição inválida

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:

Exibição de algumas informações usando o thf-info

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.

Página organizada com Grid System e com o thf-tag

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:

Todas as informações sendo exibidas na página

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>
Página organizada com thf-divider

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>
Exibindo a data formatada em dia, mês e ano

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.

Dados transformados via map do rxjs

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>
Exibindo tag com destaque

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:

Fluxo de navegação entre lista e visualização dos dados

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