Criando um CRUD com THF (3/7) - Pesquisando pelos nossos clientes
Olá mundo!
Objetivo
Implementar o mecanismo de pesquisa em nossa tela de listagem de clientes deixando-a mais funcional.
Lista de posts da série “Criando um CRUD com THF”
- Iniciando o projeto ✅
- Listando nossos clientes ✅
- Pesquisando pelos nossos clientes ✅
- Criando um novo cliente ✅
- Visualizando dados de um cliente ✅
- Atualizando um cliente ✅
- Apagando um ou mais clientes ✅
Essa lista pode sofrer alterações até o final da série. 😅
Pré-requisitos
Não deixe de ler os posts anteriores (parte 1 e 2), seria ótimo para um melhor entendimento.
Para continuar do ponto anterior, basta clonar o projeto com o que já foi implementado.
git clone --branch post-2 https://github.com/jhosefmarks/sample-thf-crud-customers.git <sua-pasta-de-trabalho>
Passo 1 — Montando nossa pesquisa
Vamos abrir o arquivo customer-list.component.ts e criar a propriedade searchTerm, que será responsável por armazenar o termo que o usuário quer usar como pesquisa em nossa página.
Além disso, vamos criar uma propriedade chamada filter do tipo ThfPageFilter, que é responsável por exibir o campo de pesquisa no cabeçalho de nossa página e disparar as funções que precisamos.
Por enquanto, vamos chamar diretamente a função que já criamos para buscar os dados do nosso backend (loadData). Dessa forma, já conseguimos ver diferenças visuais em nossa página.
Por último, vamos alterar a linha que monta a url de carga na função loadData, ou seja, vamos alterar como urlWithPagination é inicializada.
A partir de agora, além da página também estamos enviando o que o usuário digitar no campo de pesquisa.
Não podemos esquecer de atualizar o componente thf-page-list no arquivo customer-list.component.html com a propriedade t-filter.
Com isso, o visual da nossa página ficará dessa forma:
Notem que nossa página continua trazendo os resultados, mas a busca em si ainda não está funcional, pois a nossa paginação não está sendo tratada da forma correta e não estamos limpando os dados apresentados anteriormente.
Temos dois problemas para resolver:
- corrigir a paginação, sempre que efetuarmos uma nova pesquisa precisamos buscar a primeira página dos resultados retornados, e quando carregar uma nova página, precisamos re-enviar o termo pesquisado novamente para não buscarmos dados diferente do que queremos;
- precisamos limpar a lista de clientes quando uma nova pesquisa for feita, ou seja, quando for a primeira página, nós devemos zerar a nossa lista de cliente, caso contrário precisamos concatenar o resultado.
Antes de tudo, vamos criar uma nova função que será chamada quando o usuário fizer uma pesquisa.
E agora, vamos criar a função showMore e fazer com que a propriedade t-show-more do thf-table passe a chamar essa função, assim, quem passa a ser responsável por chamar nossa função que faz a requisição para o servidor (loadData) é a nova função e não o thf-table diretamente, dessa forma, ela que controla qual a próxima página que deve ser chamada.
Não esqueça de atualizar o thf-table.
Se você percebeu a função loadData, vai precisar de um refactory, já que ela deixa de ser responsável só pelo controle de paginação e passa a lidar com mais parâmetros.
Note que agora, loadData não controla mais as páginas que devem ser exibidas, também deixamos de controlar os parâmetros diretamente na url e passamos a mandar os query parameters (ou query string) como parâmetro para a função get do HttpClient fazer a concatenação necessária.
Com isso, nossa função de pesquisa rápida passa a funcionar 100%.
Passo 2 — Criando a pesquisa avançada
Agora que já temos nossa pesquisa rápida funcionando 100%, vamos criar nossa pesquisa avançada, onde o usuário poderia ter mais opções de pesquisa.
Importante: o uso de uma modal nem sempre é ou será a sua melhor opção, para fins de estudo e, para a maioria dos casos, isso já é suficiente; mas sinta-se a vontade para implementar a sua busca avançada da maneira que achar melhor.
Vamos iniciar criando um modal em nossa aplicação, abra o arquivo customer-list.component.html e inclua o thf-modal. Crie uma propriedade chamada #advancedFilter de referência para ele e configure o seu título.
Vamos criar uma função que irá abrir o nosso modal e atualizar a propriedade filter para que chame essa nova função quando o usuário quiser fazer uma pesquisa avançada, não se esqueça da propriedade que irá fazer referência ao modal que criamos no nosso template.
Com isso, já conseguimos habilitar a busca avançada e abrir um simples modal para preenchimento do usuário.
Legal, mas agora vamos trabalhar em cima do nosso formulário de pesquisa.
Como vamos trabalhar com formulário e inputs, precisamos importar o FormsModule do angular em nosso SharedModule.
Isso não vai alterar em nada o visual do nosso projeto, então, vamos ao nosso formulário.F
No arquivo customer-list.component.html, vamos incluir alguns campos para pequisa dentro no nosso modal:
nome: vamos utilizar um thf-input, pode-se dizer que é o tipo de entrada de dado mais básico que existe e vai servir para fazer pesquisas por nome.
Com isso, já teremos um resultado diferente em nosso modal.
Se você preencher o campo e apertar o botão "OK", não vai ter nenhum retorno; mas não se preocupe. Nós vamos, primeiro, criar nosso formulário e depois vamos tratar de pegar esses dados e enviar para o nosso backend.
cidade: para esse campo, vamos usa o thf-combo, que é um campo que trás uma lista de valores pré-definidos que podem ser filtrados, bem próximo a um campo com autocomplete.
Como o thf-combo precisa de uma lista pré-definida para o usuário poder escolher o valor desejado, você precisa definir essa lista no customer-list.component.ts em uma propriedade ou passar um serviço que tenha essa lista de dados, para o nosso exemplo, vamos criar nossa lista dentro do nosso código mesmo.
Com isso, nós teremos o seguinte resultado:
gênero: como o gênero tem poucas opções de escolha, em nosso exemplo vamos usar o thf-radio-group.
Da mesma forma que o thf-combo, nós precisamos configurar a lista de opções que serão exibidas pelo thf-radio-group.
Olha o resultado aí…
status: e para o campo de status vamos usar o thf-checkbox-group, pois o usuário vai poder escolher mais de uma opção.
O thf-checkbox-group segue o mesmo conceito dos componentes anteriores. Vamos ter que definir uma lista de valores válidos.
E com isso, o nosso formulário de pesquisa avançada está finalizado:
Agora, nós precisamos pegar os valores digitados pelo usuário e enviar para o nosso backend. Primeiro, vamos criar uma função que irá pegar os valores digitados pelo usuário e irá chamar nossa função loadData passando um objeto com esses valores.
Não podemos esquecer de criar no nosso componente as propriedades que estão ligadas ao ngModel dos nossos inputs.
Nossa pesquisa ainda não vai funcionar, pois faltou informar para o thf-modal que essa é a função que deve ser chamada ao confirmar a pesquisa avançada, para isso, vamos criar duas propriedades, uma para ação de confirmação e outra para a ação de cancelamento, caso o usuário desista de fazer a pesquisa avançada.
Agora, vamos configurar o thf-modal com essas novas propriedades.
Com isso, nossa função de pesquisa avançada já está funcionando!
Mas… sempre tem o mas 😅 A paginação está com problemas. Se clicarmos em "Carregar mais", os valores de pesquisa serão ignorados, então, precisamos salvar o que foi digitado ou o valor da última pesquisa avançada e enviar quando a função showMore for disparada pelo thf-table, para isso, vamos atualizar a função onConfirmAdvancedFilter para salvar os parâmetros e vamos atualizar a função showMore para enviar esses parâmetros quando o mesmo estiver preenchido.
Pronto e sem nenhum mas, nossa pesquisa avançadas está funcionando perfeitamente.
Passo 3 — Exibindo os filtros das buscas
Para deixar nossa busca ainda melhor, vamos incluir disclaimers em nossa página para o usuário saber o que está sendo filtrado, para isso vamos usar a propriedade t-disclaimer-group do thf-page-list.
Vamos criar uma propriedade em nosso componente e associar a mesma ao nosso thf-page-list.
Novamente, isso não fez nenhum efeito prático em nossa página, mas acalme-se. Queremos mostrar os disclaimers apenas quando existir alguma pesquisa ativa, quer seja ela rápida ou avançada.
Primeiro, vamos atualizar os disclaimers quando houver uma pesquisa rápida.
Com as alterações, temos o seguinte resultado:
Notem que temos um pequeno problema. Ao excluir o disclaimer, nós não atualizamos nossa tabela. Para isso, nós precisamos refazer a pesquisa sem o filtro, para resolver esse problema precisamos criar uma função que faça isso e vincular essa nova função ao nosso objeto que controla o disclaimer.
Legal, mas temos um problema aqui e vale a pena parar para entender algumas coisas. Se você colocar um debugger
dentro da função loadData, você vai perceber que ela está sendo disparada mais de uma vez. A primeira chamada acontece quando efetuamos nossa pesquisa, e a segunda acontece quando atualizamos o nosso grupo de disclaimers, fazendo com que a nossa pesquisa passe a funcionar de uma forma estranha.
O que acontece é que nosso disclaimer dispara o evento change a cada mudança, ou seja, quando recebe um disclaimer quando efetuamos uma pesquisa e quando o usuário remove um disclaimer.
Bom, isso pode parecer ruim, mas na verdade podemos usar a nosso favor. Mudando um pouco o fluxo de pesquisa nós podemos fazer com as pesquisas apenas atualizem o nosso grupo de disclaimers e quando o mesmo sofrer qualquer alteração nós disparamos a função loadData baseada no que tem no grupo de disclaimers.
Vamos ver o código refatorado.
Agora, só falta acertar nossa pesquisa avançada da mesma forma e teremos nossa funcionalidade de pesquisa 100% funcional.
Olha como o resultado final ficou bacana:
Existem outras formas de tratar o comportamento do disclaimer group, mas para o nosso exemplo, essa é a forma mais simples e prática de resolver e ainda tirar vantagem desse comportamento.
E agora José?
Agora, você pode brincar com o exemplo e adicionar novas formas de pesquisar criando filtros pré definidos entre outras opções. Uma outra ideia de implementação é limpar a pesquisa avançada quando o usuário faz a pesquisa rápida.
Você pode pegar os fontes atualizados no repositório do github. Fiz o possível para commitar passo a passo para que seja possível acompanhar a evolução do que fizemos até aqui.
No próximo post vamos começar a cadastrar nossos clientes. Vejo vocês por lá.
Referências e dicas de leitura
Documentação oficial do THF:
Documentação oficial do Angular: