quarta-feira, 11 de dezembro de 2013

Destaque (highlight) do texto filtrado na coluna do Primefaces DataTable


Neste post vou mostrar como destacar na coluna do dataTable do Primefaces o texto que o usuário digita no filtro. São 5 passos bem simples, mostrados a seguir:

i) Criar no managed bean o método removeAcentos, como foi mostrado no post anterior.

ii) Fazer um binding da tabela:

1. <p:dataTable id="Tabela"
2.                              binding="#{controlador.tabela}"


1.     private DataTable tabela;
2. 
3.     public DataTable getTabela() {
4.         return tabela;
5.     }
6. 
7.     public void setTabela(DataTable tabela) {
8.         this.tabela = tabela;
9.     }

iii) Chamar um método para retornar o texto destacado, e usar escape="false":

1. <p:column headerText="Título"
2.            filterBy="#{registro.titulo}#{controlador.removeAcentos(registro.titulo)}"
3.            filterMatchMode="contains" >
4.            <h:outputText value="#{controlador.highlight(registro.titulo,'titulo}#{controlador.removeAcentos(registro.titulo)')}"
5.                            escape="false" />
6. </p:column>

O segundo parâmetro do método é o conteúdo do filterBy sem o identificador inicial e sem a chave final (ou seja, usar somente a parte destacada em verde, ignorando as partes vermelhas):

 #{registro.   titulo}#{controlador.removeAcentos(registro.titulo)    }

Este comportamento é do médoto getFilters da tabela, como poderemos ver posteriormente no quinto passo.

iv) Criar, no managed bean, o método para montar o texto destacado:

1.     public String buildHighlight(String filtro, String texto) {
2.         String retorno = "";
3.         Integer posicao = 0, tam = filtro.length();
4.         while (true) {
5.             if (posicao > texto.length()) {
6.                 break;
7.             }
8.             if ((texto.length() - posicao) < tam) {
9.                 retorno += StringUtils.substring(texto, posicao);
10.                 break;
11.             }
12.             if (removeAcentos(StringUtils.substring(texto, posicao, posicao + tam)).equalsIgnoreCase(removeAcentos(filtro))) {
13.                 retorno += <span style="color: red;'>" + StringUtils.substring(texto, posicao, posicao + tam) + "</span>";
14.                 posicao += tam;
15.             } else {
16.                 retorno += StringUtils.substring(texto, posicao, posicao + 1);
17.                 posicao++;
18.             }
19.         }
20.         return retorno;
21.     }

v) Criar, no managed bean, o método para obter o valor digitado e retornar o destaque:

1.     public String highlight(String texto, String filtro) {
2.         String retorno = "";
3.         if (texto != null) {
4.             Map<String, String> filtros = tabela.getFilters();
5.             String textoDigitado = filtros.get(filtro);
6.             if (textoDigitado != null) {
7.                 retorno = buildHighlight(textoDigitado, texto);
8.             } else {
9.                 return texto;
10.             }
11.         }
12.         return retorno;
13.     }

Veja um exemplo que filtra o texto "Aneis" (sem acentos!) e destaca o texto encontrado (com acentos!):


Este recurso foi implementado a partir da necessidade de visualizar mais facilmente palavras que são digitadas sem acento e que aparecem no texto da coluna com acento. Quando as palavras são bem específicas, a visualização é mais fácil, mas quando são palavras pequenas e o texto da coluna tem várias linhas, o destaque mostrado acima é essencial.

terça-feira, 10 de dezembro de 2013

Como ignorar acentos usando o filtro do Primefaces


Um dos mais comuns pedidos dos usuários de sistemas é que possam pesquisar dados em tabelas sem a preocupação com acentos. Há várias maneiras de implementar esse recurso, mas vou mostrar hoje uma maneira bastante simples e direta.

Dois passos simples para filtrar dados ignorando os acentos, independente de tecnologia de bancos de dados, utilizando Primefaces:

1 - Criar um método no ManagedBean para gerar uma string sem acentos:

1.     public String removeAcentos(String s) {
2.         if (s == null) {
3.             return "";
4.         }
5.         String semAcentos = s.toLowerCase();
6.         semAcentos = semAcentos.replaceAll("[áàâãä]", "a");
7.         semAcentos = semAcentos.replaceAll("[éèêë]", "e");
8.         semAcentos = semAcentos.replaceAll("[íìîï]", "i");
9.         semAcentos = semAcentos.replaceAll("[óòôõö]", "o");
10.         semAcentos = semAcentos.replaceAll("[úùûü]", "u");
11.         semAcentos = semAcentos.replaceAll("ç", "c");
12.         semAcentos = semAcentos.replaceAll("ñ", "n");
13.         return semAcentos;
14.     }

2- Utilizar o filtro do Primefaces com uma expressão que tenha a string original (com acentos) e a string sem acentos, como pode ser visto na linha 16 abaixo:

1. <p:dataTable id="Tabela" style="width: 100%; font-size: 0.95em"
2.                                  widgetVar="wTabela"
3.                                  rowIndexVar="rownumber"
4.                                  var="item"
5.                                  value="#{bean.pessoas}"
6.                                  paginator="true"
7.                                  lazy="false"
8.                                  currentPageReportTemplate="{currentPage} de {totalPages}"
9.                                  rows="10"
10.                                  pageLinks="7"
11.                                  rowsPerPageTemplate="10,20,50,100">
12. ...
13.                         <p:column sortBy="#{item.nome}"
14.                                   style="white-space: normal"
15.                                   filterMatchMode="contains"
16.                                  filterBy="#{item.nome}#{bean.removeAcentos(item.nome)}" >
17.                                   <h:outputText value="#{item.nome}" />
18.                         </p:column>

Desta maneira, podemos pesquisar tanto José como Jose, pois a comparação vai ser feita com a string "joséjose", lembrando que o Primefaces já ignora maiúsculas e minúsculas.