page_load.js: Formatando dados em tabelas e páginas

Quando se recebe do servidor uma lista muito grande de dados (por exemplo, uma lista de itens de uma tabela do banco de dados ou um resultado de pesquisa), é necessário que esses dados sejam exibidos aos poucos ao usuário, em um formato de leitura fácil.

Neste artigo, iremos mostrar um script que lê um arquivo Json do servidor e monta uma tabela com esses dados, podendo escolher quantos itens essa tabela terá e distribuindo os itens em várias páginas.
Para conseguir isso, teremos que seguir algumas regras na construção de nossa página web. Em primeiro lugar, teremos que adicionar à página alguns campos ocultos onde armazenaremos a pagina atual, a quantidade de items por página, por qual atributo a tabela será ordenada e a quantidade total de itens:

<input type="hidden" name="pagina" value="${pagina}">
<input type="hidden" name="items" value="${items}">
<input type="hidden" name="ordem" value="${ordem}">
<input type="hidden" name="max" value="${max}">

Como falamos anteriormente, os dados serão recebidos do servidor através de um arquivo json. Para isso, usar a função $.ajax() do jQuery para ler esse arquivo, passando como parâmetro os valores dos campos ocultos acima. Assim, quando mapear o arquivo json, tenha em mente que você precisa ler esses dados. Caso esteja usando Spring, pode implementar em seu construtor um método como esse:

 @RequestMapping(value="listagem.json", method=RequestMethod.GET)
 public ModelAndView listagem_json(@RequestParam("pagina") String pagina, @RequestParam("items") String items, @RequestParam("ordem") String ordem) {
 ModelAndView mav = new ModelAndView();
 mav.setViewName(this.getName()+"/listagem");
 mav.addObject("lista", serv.listagem(pagina, items, ordem));
 return mav;
 }

Na página web, além dos campos ocultos, devemos ter as seguintes estruturas:
tabela onde os dados serão exibidos

<table class="bordered">
   <thead>
      <th class="col" data-property="..."> ... </th>
   </thead>
   <tbody class="content"> ... </tbody>
   <tfoot>
      <td class="comando" data-nome="..." data-action="..."> ... </td>
   </tfoot>
</table>

Nesta tabela, a tag thead deverá listar, através das tags th,  os atributos da entidade que será exibida (o valor de property corresponde ao nome do atributo e o conteúdo da tag será o valor a ser exibido).
A tag tbody será preenchida dinamicamente com os valores do arquivo json. Finalmente, a tag tfoot não será exibida, e serve apenas para listar comandos que poderão ser aplicados a cada item da tabela (eles serão adicionada à coluna com property=”” e terão a string

/<id_do_elemento>

adicionada ao final do valor de action).
grupo de botões para escolher quantidade de itens por página

 <div class="btn-group">
 <button type="button" class="btn btn-default items">10</button>
 <button type="button" class="btn btn-default items">20</button>
 <button type="button" class="btn btn-default items">30</button>
 <button type="button" class="btn btn-default items">40</button>
 <button type="button" class="btn btn-default items">50</button>
 </div>

Aqui o importante a ser observado é que a tag button deve ter a classe items.
caixa de seleção para escolha de atributos

 <div class="btn-group">
 <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
 Ordem <span class="caret"></span>
 </button>
 <ul class="dropdown-menu dropdown-menu-right" role="menu">
 <c:forEach var="attr" items="${atributos}" varStatus="status">
 <li><a class="ordem" href="${status.index}">${attr}</a></li>
 </c:forEach>
 </ul>
 </div>

Nesta estrutura, listaremos os atributos da entidade que estamos visualizando (esses atributos serão as colunas da tabela). Selecionando uma das opções da lista, mudaremos a ordem pela qual os itens são mostrados na tabela.
lista de páginas disponíveis

 <div align="center">
 <ul class="pagination"></ul>
 </div>

Essa estrutura será preenchida dinamicamente, assim é importante que ela possua a classe “pagination“.

O Script

Após ter finalizado a construção da página, vamos agora ver como implementar script que fará o trabalho.
Dentro de um arquivo *.js (que estamos chamando aqui de page_load.js),  devemos ter as seguintes funções:

  • load_page(…): lê o arquivo json e adiciona os itens à tabela
  • load_pagination(…): adiciona os links para as páginas, de acordo com o número total de itens e o numero de itens por página
Além dessas duas funções, devemos tratar o evento de click em cada uma das estruturas listadas acima, fazendo a alteração no campo oculto correspondente e recarregando a tabela com os novos itens.
A função load_page deve fazer o seguinte:
  1. Ler os valores dos campos ocultos
  2. Ler o arquivo json, passando o valores lidos no item 1 como parametros
  3. Para cada item do arquivo json, adicionar a tabela uma nova linha, considerando o seguinte:
    1. cada atributo do item deve ser uma coluna da tabela
    2. se o valor de property for igual a #, deixar o conteúdo da coluna em branco
    3. se o valor de property for igual um valor em branco, adicionar os comando listados na tag tfoot.

O código para essa função deve se parecer com o seguinte:

function load_content(lista, target) {
 var atributos = [];
 $(".col").each(function(){
 var property = $(this).data('property');
 atributos.push(property);
 });
 var pagina = $('input[name=pagina]').val();
 var items = $('input[name=items]').val();
 var ordem = $('input[name=ordem]').val();
 var url = lista;
 $.ajax({
 type: 'GET',
 url: url,
 data: {pagina: pagina, items: items, ordem: ordem}
 }).done(function(data){
 var json = jQuery.parseJSON( data );
 target.find("tbody.content").empty();
 $.each(json.item, function(index, item){
 var row = $('<tr>');
 var counter = 0;
 for(var i=0; i<atributos.length; i++) {
 if(atributos[i] == '#') {
 row.append('<td></td>');
 }
 else if(atributos[i] == '') {
 var col = $('<td>');
 $(".comando").each(function(){
 var nome = $(this).data("nome");
 var action = $(this).data("action");
 col.append('<button type="button" class="btn btn-sm btn-primary action" data-target="'+nome+'" data-action="'+action+'/'+item.id+'">'+nome+'</button>');
 });
 row.append(col);
 }
 else {
 var token = item[atributos[i]];
 row.append('<td>'+token+'</td>');
 }
 }
 target.find("tbody.content").append(row);
 target.find("tfoot").hide();
 counter++;
 });
 });
}

A função load_pagination irá ler o valor dos campos ocultos max e itens e irá adicionar à estrutura correspondente uma lista de links para as páginas disponíveis. O código para essa função será aproximadamente o seguinte:

function load_pagination() {
 $('.pagination').empty();
 var max = $('input[name=max]').val();
 var items = $('input[name=items]').val();
 //var paginas = Math.floor(max / items);
 var paginas = Math.round(max / items);
 if(paginas == 0) paginas = 1;
 $('.pagination').append('<li><a href="#left">&laquo;</a></li>');
 for(var i=0; i<paginas; i++) {
 var pagina = i+1;
 $('.pagination').append('<li><a class="pagina" href="#">'+pagina+'</a></li>');
 }
 $('.pagination').append('<li><a href="#right">&raquo;</a></li>');
}

Finalmente, precisamos  tratar o evento click de cada uma das estruturas auxiliares que adicionamos a nossa página. Basicamente, cada função irá alterar o valor do campo oculto correspondente e irá recarregar a tabela. O código dessas funções seria o seguinte:

$(document).on('click', '.items', function (event) {
 event.preventDefault();
 var items = $(this).text();
 $('input[name=items]').val(items);
 $('input[name=pagina]').val("1");
 var lista = $('input[name=lista]').val();
 load_content(lista, $('table.bordered'));
 load_pagination();
});
$(document).on('click', '.ordem', function (event) {
 event.preventDefault();
 var ordem = $(this).attr('href');
 $('input[name=ordem]').val(ordem);
 var lista = $('input[name=lista]').val();
 load_content(lista, $('table.bordered'));
});
$(document).on('click', '.pagina', function (event) {
 event.preventDefault();
 var pagina = $(this).text();
 var link = $(this).attr('href');
 var max = $('input[name=max]').val();
 if(link == '#left') {
 var temp = $('input[name=pagina]').val();
 if(temp > 1)
 temp = temp - 1;
 $('input[name=pagina]').val(temp);
 } else if(link == '#right') {
 var temp = $('input[name=pagina]').val();
 if(temp < max)
 temp = temp + 1;
 $('input[name=pagina]').val(temp);
 } else {
 $('input[name=pagina]').val(pagina);
 }
 var lista = $('input[name=lista]').val();
 load_content(lista, $('table.bordered'));
});