Classificação da tabela jQuery

177

Eu tenho uma tabela HTML muito simples com 4 colunas:

Facility Name, Phone #, City, Specialty

Desejo que o usuário possa classificar apenas por Nome da instalação e Cidade .

Como posso codificar isso usando jQuery?

tony noriega
fonte
Meu voto - TinyTable
redsquare

Respostas:

152

Se você quiser evitar todos os sinos e assobios, posso sugerir este sortElementsplugin simples . Uso:

var table = $('table');

$('.sortable th')
    .wrapInner('<span title="sort this column"/>')
    .each(function(){

        var th = $(this),
            thIndex = th.index(),
            inverse = false;

        th.click(function(){

            table.find('td').filter(function(){

                return $(this).index() === thIndex;

            }).sortElements(function(a, b){

                if( $.text([a]) == $.text([b]) )
                    return 0;

                return $.text([a]) > $.text([b]) ?
                    inverse ? -1 : 1
                    : inverse ? 1 : -1;

            }, function(){

                // parentNode is the element we want to move
                return this.parentNode; 

            });

            inverse = !inverse;

        });

    });

E uma demo. (clique nos cabeçalhos das colunas "cidade" e "instalação" para classificar)

James
fonte
6
A demonstração foi interrompida porque a localização do plugin foi alterada. Eu bifurquei um jsfiddle fixo para classificar elementos de demonstração que pelo menos parece funcionar para mim :) @ 999 talvez você possa atualizar sua resposta para vincular à demonstração fixa?
precisa
2
E se você tiver várias tabelas em uma página? I bifurcada a jsFiddle jsfiddle.net/CM8bT
Marc
1
Estou recebendo esse erro, Error: illegal charactero html não é exatamente o mesmo, também tenho thead e tboy, você pode me ajudar com isso, por favor?
pahnin 12/07/2012
1
A função acima não funcionará em caso de distinção entre maiúsculas e minúsculas. Neste plugin 'a'! = 'A'. Funcionaria se converter o texto em maiúsculas ou minúsculas e, em seguida, marque e compare. Por exemplo: em vez de $.text([a]) == $.text([b])usar, $.text([a]).toUpperCase() == $.text([b]).toUpperCase()será corrigido.
NBK
1
Logo você descobrirá que a classificação não é um problema específico para a tabela - quando o fizer, aqui está meu minúsculo plug-in jQuery, que classificará listas, tabelas, divs ou qualquer outra coisa, em ordem crescente ou decrescente. Também o usei para classificar por tipos de dados diferentes, como moeda ou ano - basta fornecer sua própria função que retorna os dados para classificação. (Eu gosto de manter as funções separar, e dar-lhes nomes significativos, para construir a minha própria pequena biblioteca de "maneiras de classificar as coisas" que são específicos para a solução que eu estou construindo.)
mindplay.dk
184

Me deparei com isso, e pensei em jogar meus 2 centavos. Clique nos cabeçalhos das colunas para classificar em ordem crescente e novamente para classificar em ordem decrescente.

  • Funciona no Chrome, Firefox, Opera E IE (8)
  • Usa apenas JQuery
  • Faz classificação alfa e numérica - ascendente e descendente

$('th').click(function(){
    var table = $(this).parents('table').eq(0)
    var rows = table.find('tr:gt(0)').toArray().sort(comparer($(this).index()))
    this.asc = !this.asc
    if (!this.asc){rows = rows.reverse()}
    for (var i = 0; i < rows.length; i++){table.append(rows[i])}
})
function comparer(index) {
    return function(a, b) {
        var valA = getCellValue(a, index), valB = getCellValue(b, index)
        return $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.toString().localeCompare(valB)
    }
}
function getCellValue(row, index){ return $(row).children('td').eq(index).text() }
table, th, td {
    border: 1px solid black;
}
th {
    cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
    <tr><th>Country</th><th>Date</th><th>Size</th></tr>
    <tr><td>France</td><td>2001-01-01</td><td>25</td></tr>
    <tr><td><a href=#>spain</a></td><td>2005-05-05</td><td></td></tr>
    <tr><td>Lebanon</td><td>2002-02-02</td><td>-17</td></tr>
    <tr><td>Argentina</td><td>2005-04-04</td><td>100</td></tr>
    <tr><td>USA</td><td></td><td>-6</td></tr>
</table>

** Atualização: 2018

Nick Grealy
fonte
10
Fantástico! Observe que se você tiver links nos tds, por exemplo, <a href="#">Test</a>a classificação diz respeito a <a.... Para classificar apenas por texto, você precisa alterar html()na última linha para text().
Kai Noack
1
@wubblyjuggly - o que você tentou? Atualmente, a tabela usa os dados da célula (por exemplo, valor html) para determinar o tipo de dados (por exemplo, número ou sequência). Como as strings de data vêm em muitos formatos, é impraticável escrever um detector / analisador genérico de data (você pode reescrever comparer(..)se souber exatamente qual formato deseja suportar). Enquanto isso, se você yyyy-MM-dd" string" usar , a classificação ordenará os dados para você. por exemplo jsbin.com/pugedip/1
Nick Grealy
1
Este exemplo funcionou perfeitamente para mim onde a solução escolhida não funcionou. A resposta escolhida não funcionou para mim; Não tenho certeza se é porque estou usando um thead / tbody ou não (o jsfiddle, sem essas tags, funcionou).
RalphTheWonderLlama
1
Obrigado @Jan, incorporei sua sugestão na solução!
Nick Grealy
1
@NickGrealy Você está certo minhas sugestões no comentário, onde exatamente a edição rejeitada. Compare jsfiddle.net/gn1vtcLq/2 (minha versão) com jsfiddle.net/0a15ky9u (sua versão). Clique no cabeçalho "Sexo" várias vezes para ver os IDs ou Nomes subseqüentemente alterando a ordem na sua versão, mantendo a ordem inicial na minha versão.
Markus s
39

De longe, o mais fácil que eu usei é: http://datatables.net/

Surpreendentemente simples ... apenas certifique-se de seguir a rota de substituição do DOM (IE, construindo uma tabela e permitindo que o DataTables a reformate) e certifique-se de formatar sua tabela <thead>e <tbody>ou ela não funcionará. Essa é a única pegadinha.

Também há suporte para AJAX, etc. Como em todos os códigos realmente bons, também é MUITO fácil desativar tudo. Você ficaria surpreso com o que poderia usar. Comecei com uma DataTable "vazia" que classificou apenas um campo e depois percebi que alguns dos recursos eram realmente relevantes para o que estou fazendo. Os clientes adoram os novos recursos.

Pontos de bônus para DataTables para suporte completo ao ThemeRoller ....

Eu também tive sorte com o tablesorter, mas não é tão fácil, nem tão bem documentado e possui apenas recursos ok.

bpeterson76
fonte
4
Concordou que é um bom plugin rico em recursos, mas possivelmente exagere em termos de complexidade e tamanho para o que o OP exige.
Redsquare #
2
+1 por estar disponível no NuGet: nuget.org/List/Packages/jquery.datatables
Frank van Eykelen
1
Concordo também, o datatables.net é o melhor classificador / paginizador / pesquisador de tabelas existente. Seus recursos ricos me pouparam muito tempo. Só lamento o tempo que passei tentando integrar tablesorter2 plugin para meus códigos antes de descobrir sobre datatables ...
Logan
2
Eu sei que este é um tópico antigo, mas esta resposta ainda se aplica. Provavelmente o plugin mais fácil que já usei. Levou 5 minutos para levantar e ordenar minha mesa. Obrigado!
Trucktech
Muito fácil de configurar, melhor que já usei.
Rog
18

Acabamos de começar a usar esta ferramenta: https://plugins.jquery.com/tablesorter/

Há um vídeo sobre seu uso em: http://www.highoncoding.com/Articles/695_Sorting_GridView_Using_JQuery_TableSorter_Plug_in.aspx

    $('#tableRoster').tablesorter({
        headers: {
            0: { sorter: false },
            4: { sorter: false }
        }
    });

Com uma mesa simples

<table id="tableRoster">
        <thead> 
                  <tr>
                    <th><input type="checkbox" class="rCheckBox" value="all" id="rAll" ></th>
                    <th>User</th>
                    <th>Verified</th>
                    <th>Recently Accessed</th>
                    <th>&nbsp;</th>
                  </tr>
        </thead>
Ravi Ram
fonte
15

Minha resposta seria "tenha cuidado". Muitos complementos de classificação de tabelas do jQuery classificam apenas o que você passa para o navegador. Em muitos casos, você deve ter em mente que as tabelas são conjuntos dinâmicos de dados e podem conter um zilhão de linhas de dados.

Você menciona que possui apenas 4 colunas, mas, muito mais importante, não menciona quantas linhas estamos falando aqui.

Se você passar 5000 linhas para o navegador a partir do banco de dados, sabendo que a tabela de banco de dados real contém 100.000 linhas, minha pergunta é: qual é o sentido de tornar a tabela classificável? Para fazer uma classificação adequada, você precisará enviar a consulta de volta ao banco de dados e permitir que o banco de dados (uma ferramenta realmente projetada para classificar dados) faça a classificação por você.

Em resposta direta à sua pergunta, o melhor complemento de classificação que eu me deparei é a Ingrid. Há muitas razões pelas quais eu não gosto desse complemento ("sinos e assobios desnecessários ..." como você o chama), mas um de seus melhores recursos em termos de classificação é que ele usa ajax e não Não presuma que você já passou todos os dados antes de fazer sua classificação.

Reconheço que esta resposta provavelmente é um exagero (e com mais de 2 anos de atraso) para seus requisitos, mas fico aborrecido quando os desenvolvedores da minha área ignoram esse ponto. Então, espero que outra pessoa compreenda.

Eu me sinto melhor agora.

cartbeforehorse
fonte
6

Adoro essa resposta aceita, no entanto, raramente você obtém requisitos para classificar html e não precisa adicionar ícones indicando a direção da classificação. Peguei o exemplo de uso da resposta de aceitação e o corrigi rapidamente, simplesmente adicionando bootstrap ao meu projeto e adicionando o seguinte código:

<div></div>

dentro de cada um <th>para que você tenha um lugar para definir o ícone.

setIcon(this, inverse);

do uso da resposta aceita, abaixo da linha:

th.click(function () {

e adicionando o método setIcon:

function setIcon(element, inverse) {

        var iconSpan = $(element).find('div');

        if (inverse == false) {
            $(iconSpan).removeClass();
            $(iconSpan).addClass('icon-white icon-arrow-up');
        } else {
            $(iconSpan).removeClass();
            $(iconSpan).addClass('icon-white icon-arrow-down');
        }
        $(element).siblings().find('div').removeClass();
    }

Aqui está uma demonstração . - Você precisa executar a demonstração no Firefox ou IE ou desativar a verificação do tipo MIME do Chrome para que a demonstração funcione. Depende do plug-in sortElements, vinculado pela resposta aceita, como um recurso externo. Apenas um alerta!


fonte
6

Esta é uma boa maneira de classificar uma tabela:

$(document).ready(function () {
                $('th').each(function (col) {
                    $(this).hover(
                            function () {
                                $(this).addClass('focus');
                            },
                            function () {
                                $(this).removeClass('focus');
                            }
                    );
                    $(this).click(function () {
                        if ($(this).is('.asc')) {
                            $(this).removeClass('asc');
                            $(this).addClass('desc selected');
                            sortOrder = -1;
                        } else {
                            $(this).addClass('asc selected');
                            $(this).removeClass('desc');
                            sortOrder = 1;
                        }
                        $(this).siblings().removeClass('asc selected');
                        $(this).siblings().removeClass('desc selected');
                        var arrData = $('table').find('tbody >tr:has(td)').get();
                        arrData.sort(function (a, b) {
                            var val1 = $(a).children('td').eq(col).text().toUpperCase();
                            var val2 = $(b).children('td').eq(col).text().toUpperCase();
                            if ($.isNumeric(val1) && $.isNumeric(val2))
                                return sortOrder == 1 ? val1 - val2 : val2 - val1;
                            else
                                return (val1 < val2) ? -sortOrder : (val1 > val2) ? sortOrder : 0;
                        });
                        $.each(arrData, function (index, row) {
                            $('tbody').append(row);
                        });
                    });
                });
            });
            table, th, td {
            border: 1px solid black;
        }
        th {
            cursor: pointer;
        }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
        <tr><th>id</th><th>name</th><th>age</th></tr>
        <tr><td>1</td><td>Julian</td><td>31</td></tr>
        <tr><td>2</td><td>Bert</td><td>12</td></tr>
        <tr><td>3</td><td>Xavier</td><td>25</td></tr>
        <tr><td>4</td><td>Mindy</td><td>32</td></tr>
        <tr><td>5</td><td>David</td><td>40</td></tr>
    </table>

O violino pode ser encontrado aqui:
https://jsfiddle.net/e3s84Luw/

A explicação pode ser encontrada aqui: https://www.learningjquery.com/2017/03/how-to-sort-html-table-using-jquery-code

Julian
fonte
2

A resposta de @Nick Grealy é ótima, mas não leva em consideração os possíveis rowspanatributos das células do cabeçalho da tabela (e provavelmente as outras respostas também não o fazem). Aqui está uma melhoria da resposta de @Nick Grealy que corrige isso. Com base nesta resposta também (obrigado @Andrew Orlov).

Também substituí a $.isNumericfunção por uma personalizada (obrigado @zad) para fazê-la funcionar com versões mais antigas do jQuery.

Para ativá-lo, adicione class="sortable"à <table>tag.

$(document).ready(function() {

    $('table.sortable th').click(function(){
        var table = $(this).parents('table').eq(0);
        var column_index = get_column_index(this);
        var rows = table.find('tbody tr').toArray().sort(comparer(column_index));
        this.asc = !this.asc;
        if (!this.asc){rows = rows.reverse()};
        for (var i = 0; i < rows.length; i++){table.append(rows[i])};
    })

});

function comparer(index) {
    return function(a, b) {
        var valA = getCellValue(a, index), valB = getCellValue(b, index);
        return isNumber(valA) && isNumber(valB) ? valA - valB : valA.localeCompare(valB);
    }
}
function getCellValue(row, index){ return $(row).children('td').eq(index).html() };

function isNumber(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

function get_column_index(element) {
    var clickedEl = $(element);
    var myCol = clickedEl.closest("th").index();
    var myRow = clickedEl.closest("tr").index();
    var rowspans = $("th[rowspan]");
    rowspans.each(function () {
        var rs = $(this);
        var rsIndex = rs.closest("tr").index();
        var rsQuantity = parseInt(rs.attr("rowspan"));
        if (myRow > rsIndex && myRow <= rsIndex + rsQuantity - 1) {
            myCol++;
        }
    });
    // alert('Row: ' + myRow + ', Column: ' + myCol);
    return myCol;
};
Dennis Golomazov
fonte
E se você ordenar por data?
precisa saber é o seguinte
@wubblyjuggly você pode substituir a função comparer com aquele que compara datas, ver, por exemplo stackoverflow.com/questions/10636779/jquery-date-sorting
Dennis Golomazov
1
Bravo, eu tentei dezenas de classificadores, o seu é o único que funciona para mim. Entre minhas datas estão no formato de texto (2020.02.23), por isso não é um problema para mim
Manny Ramirez
2

Você pode usar um plugin jQuery ( breedjs ) que fornece classificação, filtro e paginação:

HTML:

<table>
  <thead>
    <tr>
      <th sort='name'>Name</th>
      <th>Phone</th>
      <th sort='city'>City</th>
      <th>Speciality</th>
    </tr>
  </thead>
  <tbody>
    <tr b-scope="people" b-loop="person in people">
      <td b-sort="name">{{person.name}}</td>
      <td>{{person.phone}}</td>
      <td b-sort="city">{{person.city}}</td>
      <td>{{person.speciality}}</td>
    </tr>
  </tbody>
</table>

JS:

$(function(){
  var data = {
    people: [
      {name: 'c', phone: 123, city: 'b', speciality: 'a'},
      {name: 'b', phone: 345, city: 'a', speciality: 'c'},
      {name: 'a', phone: 234, city: 'c', speciality: 'b'},
    ]
  };
  breed.run({
    scope: 'people',
    input: data
  });
  $("th[sort]").click(function(){
    breed.sort({
      scope: 'people',
      selector: $(this).attr('sort')
    });
  });
});

Exemplo de trabalho em violino

João Paulo
fonte
2

Este não desliga o navegador, é fácil de configurar:

var table = $('table');

$('th.sortable').click(function(){
    var table = $(this).parents('table').eq(0);
    var ths = table.find('tr:gt(0)').toArray().sort(compare($(this).index()));
    this.asc = !this.asc;
    if (!this.asc)
       ths = ths.reverse();
    for (var i = 0; i < ths.length; i++)
       table.append(ths[i]);
});

function compare(idx) {
    return function(a, b) {
       var A = tableCell(a, idx), B = tableCell(b, idx)
       return $.isNumeric(A) && $.isNumeric(B) ? 
          A - B : A.toString().localeCompare(B)
    }
}

function tableCell(tr, index){ 
    return $(tr).children('td').eq(index).text() 
}
raptor
fonte
1
Essa parece a melhor solução. Não requer um plugin. A primeira linha que você pode excluir e, em seu documento, cole o bloco $ ('th.sortable') .clique em (...). Dê aos cabeçalhos da tabela a classe classificável e pronto. <th class = 'classificável> título </th>. Funciona encantador para colunas com texto ou números.
Pizzamonster
1

À resposta de James, mudarei apenas a função de classificação para torná-la mais universal. Dessa forma, ele classificará o texto em ordem alfabética e os números como números.

if( $.text([a]) == $.text([b]) )
    return 0;
if(isNaN($.text([a])) && isNaN($.text([b]))){
    return $.text([a]) > $.text([b]) ? 
       inverse ? -1 : 1
       : inverse ? 1 : -1;
}
else{
    return parseInt($.text([a])) > parseInt($.text([b])) ? 
      inverse ? -1 : 1
      : inverse ? 1 : -1;
}
Kaloyan Iliev
fonte
1

Outra abordagem para classificar a tabela HTML. (com base na classificação HTML do W3.JS )

/* Facility Name */
$('#bioTable th:eq(0)').addClass("control-label pointer");
/* Phone # */
$('#bioTable th:eq(1)').addClass("not-allowed");
/* City */
$('#bioTable th:eq(2)').addClass("control-label pointer");
/* Specialty */
$('#bioTable th:eq(3)').addClass("not-allowed");


var collection = [{
  "FacilityName": "MinION",
  "Phone": "999-8888",
  "City": "France",
  "Specialty": "Genetic Prediction"
}, {
  "FacilityName": "GridION X5",
  "Phone": "999-8812",
  "City": "Singapore",
  "Specialty": "DNA Assembly"
}, {
  "FacilityName": "PromethION",
  "Phone": "929-8888",
  "City": "San Francisco",
  "Specialty": "DNA Testing"
}, {
  "FacilityName": "iSeq 100 System",
  "Phone": "999-8008",
  "City": "Christchurch",
  "Specialty": "gDNA-mRNA sequencing"
}]

$tbody = $("#bioTable").append('<tbody></tbody>');

for (var i = 0; i < collection.length; i++) {
  $tbody = $tbody.append('<tr class="item"><td>' + collection[i]["FacilityName"] + '</td><td>' + collection[i]["Phone"] + '</td><td>' + collection[i]["City"] + '</td><td>' + collection[i]["Specialty"] + '</td></tr>');
}
.control-label:after {
  content: "*";
  color: red;
}

.pointer {
  cursor: pointer;
}

.not-allowed {
  cursor: not-allowed;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.w3schools.com/lib/w3.js"></script>
<link href="https://www.w3schools.com/w3css/4/w3.css" rel="stylesheet" />
<p>Click the <strong>table headers</strong> to sort the table accordingly:</p>

<table id="bioTable" class="w3-table-all">
  <thead>
    <tr>
      <th onclick="w3.sortHTML('#bioTable', '.item', 'td:nth-child(1)')">Facility Name</th>
      <th>Phone #</th>
      <th onclick="w3.sortHTML('#bioTable', '.item', 'td:nth-child(3)')">City</th>
      <th>Specialty</th>
    </tr>
  </thead>
</table>

Penny Liu
fonte
1

Acabei usando a resposta de Nick (a mais popular, mas não aceita) https://stackoverflow.com/a/19947532/5271220

e combinou-o com o https://stackoverflow.com/a/16819442/5271220, mas não quis adicionar ícones ou fontawesome ao projeto. Os estilos CSS para sort-column-asc / desc Eu fiz cores, preenchimentos, bordas arredondadas.

Também o modifiquei para ir por classe e não por qualquer, para podermos controlar quais são classificáveis. Isso também pode ser útil mais tarde, se houver duas tabelas, embora mais modificações precisem ser feitas para isso.

corpo:

 html += "<thead>\n";
    html += "<th></th>\n";
    html += "<th class=\"sort-header\">Name <span></span></i></th>\n";
    html += "<th class=\"sort-header\">Status <span></span></th>\n";
    html += "<th class=\"sort-header\">Comments <span></span></th>\n";
    html += "<th class=\"sort-header\">Location <span></span></th>\n";
    html += "<th nowrap class=\"sort-header\">Est. return <span></span></th>\n";
    html += "</thead>\n";
    html += "<tbody>\n"; ...

... mais abaixo no corpo

$("body").on("click", ".sort-header", function (e) {
    var table = $(this).parents('table').eq(0)
    var rows = table.find('tr:gt(0)').toArray().sort(comparer($(this).index()))
    this.asc = !this.asc
    if (!this.asc) { rows = rows.reverse() }
    for (var i = 0; i < rows.length; i++) { table.append(rows[i]) }

    setIcon(e.target, this.asc);
});

funções:

function comparer(index) {
        return function (a, b) {
            var valA = getCellValue(a, index), valB = getCellValue(b, index)
            return $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.toString().localeCompare(valB)
        }
    }

    function getCellValue(row, index) {
        return $(row).children('td').eq(index).text()
    }

    function setIcon(element, inverse) {

        var iconSpan = $(element).find('span');

        if (inverse == true) {
            $(iconSpan).removeClass();
            $(iconSpan).addClass('sort-column-asc');
            $(iconSpan)[0].innerHTML = " &#8593 " // arrow up
        } else {
            $(iconSpan).removeClass();
            $(iconSpan).addClass('sort-column-desc');
            $(iconSpan)[0].innerHTML = " &#8595 " // arrow down 
        }

        $(element).siblings().find('span').each(function (i, obj) {
            $(obj).removeClass();
            obj.innerHTML = "";
        });
    }
Skwirl cego
fonte
-4

Meu voto! jquery.sortElements.js e jquery simples
Muito simples, muito fácil, obrigado nandhp ...

            $('th').live('click', function(){

            var th = $(this), thIndex = th.index(), var table = $(this).parent().parent();

                switch($(this).attr('inverse')){
                case 'false': inverse = true; break;
                case 'true:': inverse = false; break;
                default: inverse = false; break;
                }
            th.attr('inverse',inverse)

            table.find('td').filter(function(){
                return $(this).index() === thIndex;
            }).sortElements(function(a, b){
                return $.text([a]) > $.text([b]) ?
                    inverse ? -1 : 1
                    : inverse ? 1 : -1;
            }, function(){
                // parentNode is the element we want to move
                return this.parentNode; 
            });
            inverse = !inverse;     
            });

Dei uma melhorada do código
One cod better! Função para Todas as tabelas em todos os Th em todos os tempos ... Olha!
DEMO

Filipe Rudá
fonte
3
Além de não ser capaz de entender uma palavra, eu recomendaria fortemente contra .live().
encarnada