Procurar

Categorias

Posts recentes

Arquivo

Blog feeds

Bookmarks


Classificando o conteúdo de uma tabela como num data-grid
sexta, 1 de dezembro de 2006

Vou mostrar neste artigo uma função para reorganizar as linhas de uma tabela a partir dos valores de suas colunas. Tive dúvidas sobre um título que dissesse isso em uma linha, mas achei que a idéia do data-grid ilustraria bem. A idéia é olhar a tabela por suas colunas e, a partir de um click no elemento <th> correspondente, classificar e reorganizar as linhas pelos valores na coluna escolhida.

Esse script foi criado a partir de um exemplo que consegui na internet há anos, não sei, mas se não me engano foi num site da Microsoft. Não havia informações autorais, mas a verdade é que quando digo "criado a partir de" significa que mudei bem a coisa.
O legal da função é que usa propriedades e métodos nativos do elemento <table> e de seus sub elementos, que quase não se vê e não são muito utilizados - coisa antiga, da época em que "Dom" era só para quem tinha algum talento especial e "Ajax" não passava de material de limpeza (rsrsrs).

Pois é, mas voltando ao presente, a semântica nos diz que as tabelas não são para criar estruturas de design, como se usava, mas para exibir dados "tabulares", aqueles que estamos acostumados a ver em forma de "planilhas", no Exel por exemplo. E junto com essa idéia, funções específicas foram criadas para que os dados exibidos tivessem alguma mobilidade. Propriedades como Table.rows, Table.cols, Table.tbody, Table.tBodies… quem usa isso? Bem, eu não. Mas adorei conhecê-las.

A função sortTable() deve ser definida como uma propriedade do(s) elemento(s) <table> em questão, dessa forma todos os dados estarão acessíveis, pois serão membros do mesmo objeto - isso deve acontecer no onload ou num script colocado abaixo do elemento, quando a tabela já existe efetivamente. Um detalhe importante é que precisaremos do também quase esquecido elemento <tbody>, que também possui a propriedade rows. Isso por quê dessa forma delimitamos o conteúdo a ser classificado, excluindo os cabeçalhos das colunas - senão ao clicar, o <th> - que também é incluído no objeto rows, entra na dança e pode ir para em qualquer linha, de acordo com seu texto.
A função lê o conteúdo do primeiro tbody da tabela - digo isso por que é lícito usar mais de um tbody em uma mesma tabela. Não iria funcionar direito.

Fazemos um loop pelas rows da tabela, colocando-os em um array, na mesma seqüência. Aí está o "segredo" da classificação: basta usar os métodos sort() e reverse() do objeto Array. Depois de rearrumar o array, refazemos a tabela a partir dele. Veremos que há duas funções necessárias para que sortTable funcione: generateCompareTRs - usada como parâmetro para o método Array.sort - e getColValue, que só aparecerá mais adiante. Veja a função principal:

function sortTable(iCol) {
var oTBody = this.tBodies[0]; // pega o tbody
var colDataRows = oTBody.rows; // pega as linhas
var oFragment = document.createDocumentFragment(); // será usado para refazer a ordem
var aTRs = []; // array para receber as linhas
  for(var i = 0; i < colDataRows.length; i++) aTRs[i] = colDataRows[i];

  if(this.sortCol == iCol) aTRs.reverse();
  else aTRs.sort(generateCompareTRs(iCol));

  for (var i=0; i < aTRs.length; i++) oFragment.appendChild(aTRs[i]);

oTBody.appendChild(oFragment);
this.sortCol = iCol;
}

A função generateCompareTRs() recebe o índice da coluna que servirá como base para a classificação e retorna uma outra função que será enviada para o método sort. Ela determina, segundo os valores a serem comparados, se a comparação será numérica ou baseada em strings e a função retornada será apropriada para os valores da coluna em questão.

function generateCompareTRs(iCol) {
  var ret = function(oTR1, oTR2) {
    if(typeof(getColValue(oTR1.cells[iCol])) == "number" &&
       typeof(getColValue(oTR2.cells[iCol])) == "number")
      return getColValue(oTR1.cells[iCol]) - getColValue(oTR2.cells[iCol]);
  return   getColValue(oTR1.cells[iCol]).localeCompare(getColValue(oTR2.cells[iCol]));
  };
return ret;
};

Além dela há também a função getColValue(), que recebe um elemento <td> e busca por um conteúdo classificável. Veja a ordem de precedência no retorno da função:

  • se há apenas texto, retorna o texto
  • se há texto e TAGs, retorna apenas o texto
  • se não há texto:
    • se há (na TD) o atributo "title", retorna seu valor
    • se o 1º elemento da TD é uma IMG:
      • se há o atributo "title", retorna seu valor
      • se há o atributo "alt", retorna seu valor
      • se não há alt nem title, retorna o atributo "src" da imagem
  • se não é nenhum dos casos acima, retorna uma string vazia

Vejamos a getColValue():

function getColValue(col) {
var ret = col.innerHTML.replace(/<[^>]*>/g,"");
  if(/^\s*$/.test(ret)) {
    if(/\w+/.test(col.title)) ret = col.title;
    else if(/^img$/i.test(col.firstChild.tagName))
      ret = col.firstChild.title || col.firstChild.alt || col.firstChild.src;
  else ret = "";
  }
return /^\d+$/.test(ret) ? parseInt(ret) : ret;
}

Claro que se poderia fazer o mesmo usando apenas o DOM, mas é mais simples assim e estamos falando de IE 4 e NS 6 - praticamente não há falta de suporte dos navegadores. Contradizendo isso, a função generateCompareTRs usa o método localeCompare, da versão 5.6 do Javascript…

Independente de preferências, considero a função bastante útil e espero que seja de ajuda para alguém.

Veja aqui uma página de testes

2 Comentários »

Feeds para os comentários nesse post:
TrackBack: http://cauguanabara.blogsome.com/2006/12/01/classificando-o-conteudo-de-uma-tabela-como-num-data-grid/trackback/

  1. Muito interessante essa função. Vai ajudar muito em minha pesquisa. Bem documentada as linhas de instruções. Acabo de encontrar uma fonte confiável de exemplos e explicações que realmente funcionam. Grato.

    Por Rodrigo em 2006-12-01 09:45:32, sexta

  2. Achei interessante!! estava procurando uma função assim faz tempo! eheheeh.
    Vc teria um exemplo de como selecionar a linha em que eu clicar e pegar o id dessa linha? Como se fosse para editar a linha e salva-la no banco?
    Bem agradeço de já por essa função.

    Por Ivan em 2006-12-01 09:45:32, sexta

Say something! »















Por favor digite o texto da imagem acima.

lamp! Mapa do site
Classificando o conteúdo de uma tabela como num data-grid