Spis treści:

Kategoria:HTMLJavaScript


Sortowanie tabeli w HTML i JavaScript - cz.2

Na początku chomik nie lubił odkurzacza...

    ...ale potem się wciągnął.

Sortowanie tabeli z dodatkami

Jakiś czas temu zaprezentowałem w artykule Sortowanie tabeli w HTML i JavaScript - cz.1 technikę, dzięki której tabele uzyskają możliwość sortowania. W drugiej części, również poświęconej sortowaniu tabel przy pomocy JavaScript, zajmę się udoskonalaniem wcześniej napisanych funkcji. Zanim przejdziemy dalej, warto zapoznać się z poprzednim wpisem. Nie będę tym razem wszystkiego wyjaśniał, bo wiele z użytych technik pozostanie bez żadnych zmian. Powiem więcej - więcej pozostanie niż ulegnie zmianie.

Jaki jest zatem plan? Poprzednia tabela nie różniła się niczym od zwykłej tabeli i użytkownik mógł nie wiedzieć, że dane są w jakiś sposób posortowane. Coś niby się przestawiło, ale nie da się na pierwszy rzut oka wskazać, która z kolumn jest posortowana i w jakiej kolejności. Plan jest zatem następujący: oznaczyć kolumnę, która będzie posortowana i oznaczyć kolejność tego sortowania.

Funkcje pomocnicze

Nie od razu Rzym zbudowano. Tak i tym razem zacznę od funkcji pomocniczych, by na końcu przedstawić dzieło ostateczne. Pomysł polega na tym, aby do nagłówka, który został kliknięty dodać znacznik. Znacznik taki będzie zawierał jeden z dwóch symboli: B2; lub BC;. Jasne jest, co te symbole reprezentują. Jakie będą nam potrzebne funkcje? Wcześniej zmieniając kolejność sortowania zmienialiśmy tylko atrybut order klikniętego nagłówka. Teraz trzeba zrobić coś więcej: dodać symbol, który będzie nam reprezentował taki sposób sortowania graficznie. Podobnie należy postąpić przy anulowaniu atrybutu order - trzeba taki symbol graficzny usunąć. Te operacje będą wykonywane przez parę funkcji SetOrder i ResetOrder. Zanim jednak do nich przejdę przyjrzyjmy się nieco zmienionej funkcji attachSorting.

function attachSorting(){
  var handlers=[['SSort', ValueSort],['ISort',IntegerSort]];
  for(var i=0, ths=document.getElementsByTagName('th'); th=ths[i]; i++){
    for (var h=0; h<handlers.length;h++) {
      if(Contains(th.className.split(" "), handlers[h][0])){
        th.columnIndex=i;
        th.order=-1;
        th.sortHandler = handlers[h][1];
        th.onclick=function(){sort(this);}
        var divNode = document.createElement('div');
        var textNode = document.createTextNode('');
        divNode.appendChild(textNode);
        th.appendChild(divNode);
        th.sortTextNode = textNode;

      }
    }
  }
}

Na listingu wyróżniono fragmenty, które zostały dodane. Jakie jest ich zadanie? Dodajemy do każdego naglówka, który może być sortowany, znacznik div z elementem tekstowym w środku. Ten element tekstowy zapamiętujemy sobie w atrybucie sortTextNode nagłówka. Przyda nam się to w dalszej części.

Tak przygotowani możemy przystąpić do napisania dwóch wspomnianych funkcji pomocniczych: SetOrder i ResetOrder. Ich kod został zaprezentowany poniżej:

function SetOrder(th){
  th.order *= -1;
  th.sortTextNode.nodeValue=th.order<0?'\u25B2':'\u25BC';
}
function ResetOrder(th){
  th.sortTextNode.nodeValue='';
  th.order=-1;
}

Tak przygotowani możemy przejść do części właściwej.

Graficzna reprezentacja sortowania

Popatrzmy, w jaki sposób zmodyfikowana została funkcja sort. Cały kod pokazany jest poniżej:

function sort(header){
    SetOrder(header);
    var table = header.parentNode.parentNode;
    for (var i=0, th, ths=table.getElementsByTagName('th'); th=ths[i]; i++)
      if (th.order && th!=header)
        ResetOrder(th);
    var rows=table.getElementsByTagName('tr');
    for(var i=1, tempRows=[], tr; tr=rows[i]; i++){tempRows[i-1]=tr}
    tempRows.sort(function(a,b){
      return header.order*
        (header.sortHandler(
          a.getElementsByTagName('td')[header.columnIndex].innerHTML,
          b.getElementsByTagName('td')[header.columnIndex].innerHTML)?1:-1)});
    for(var i=0; i<tempRows.length; i++){
        table.appendChild(tempRows[i]);
    }
}

Większość została już opisana w części pierwszej. Tak prawdę mówiąc, zmieniły się tylko instrukcje zmieniające atrybut order. Zmieniły się na wywołania dwóch wspomnianych funkcji pomocniczych: SetOrder i ResetOrder. To wszystko. Dzięki naszemu atrybutowi sortTextNode nagłówka zmiana symbolu jest wyjątkowo prosta. Można się zastanawiać, czy funkcje SetOrder i ResetOrder są potrzebne. W tym przypadku jest to pewnie przerost formy nad treścią, ale zastosowałem takie rozwiązanie z prostego powodu: cała logika zmian w strukturze DOM przeniesiona została do tych dwóch funkcji. Przykład pokazuje, jak wstawić prosty symbol, ale polecam bardziej skomplikowane zabawy - zmianę tła, umieszczenie obrazka, zmianę stylu. Algorytm sortowania (funkcja sort) nie powinna się w takim przypadku zmieniać.

Zaprezentowane rozwiązanie ma jeszcze jedną drobną wadę: Kliknięcie w nagłówek i wstawienie symbolu powoduje rozciąganie się kolumny - potrzebne jest przecież miejsce na symbol graficzny. Poza tym, znacznik div domyślnie łamie linię. Aby zapobiec takiemu zjawisku wystarczy ustawić odpowiednie style. Ot choćby takie, jakie pokazano poniżej:

<style>
.ISort,.SSort{cursor: pointer;}
.ISort div, .SSort div{display: inline-block;width: 20px;}
</style>

Przykład działania

Przed nami czynność najważniejsza - przetestowanie całego zmodyfikowanego kodu. Użyję tej samej tabeli co w części pierwszej.

<table>
<tr><th class="ISort">Integer</th><th class="SSort">String</th><th class="SSort">Domyślne</th><th>Inne</th></tr>
<tr><td>2</td><td>A</td><td>2</td><td>Dodatkowe dane 1</td></tr>
<tr><td>10</td><td>B</td><td>10</td><td>Dodatkowe dane 2</td></tr>
<tr><td>3</td><td>G</td><td>3</td><td>Dodatkowe dane 3</td></tr>
<tr><td>111</td><td>D</td><td>111</td><td>Dodatkowe dane 4</td></tr>
</table>

Rezultat będzie następujący:

IntegerStringDomyślneInne
2A2Dodatkowe dane 1
10B10Dodatkowe dane 2
3G3Dodatkowe dane 3
111D111Dodatkowe dane 4

Różnica jest niewielka, ale użyteczności nie sposób odmówić.

Podsumowanie

Tabela wydaje się być gotowa i na tym etapie poprzestanę. Można oczywiście dalej udoskonalać skrypty i dać użytkonikom jeszcze doskonalsze dzieło, ale nie będę się tym już zajmował. Chyba, że zajdzie taka potrzeba, czego wykluczyć nie można. W najbliższym czasie pokażę, jak można uzyskać podobny rezultat przy pomocy biblioteki jQuery. Przekonamy się, jak bardzo nam to uprości cały proces.

Kategoria:HTMLJavaScript

, 2013-12-20

Komentarze:

Momo (2015-09-09 12:59:50)
Skopiowałem cały kod, postępowałem zgodnie z instrukcjami, ale niestety nie działa :(
PD (2015-09-18 15:32:25)
Mam w takim razie dwa rozwiązania:
1. Skorzystanie z narzędzi programistycznych i prześledzenie kodu (być może w konsoli są jakieś informacje o błędach),
2. Kliknięcie prawym przyciskiem myszy i obejrzenia źródeł tej strony - być może są jakieś drobne błędy.
Więcej bez zobaczenia konkretnego przypadku nie pomogę.
red57 (2016-02-28 14:02:42)
U mnie działa. Dzięki.
lukasL (2017-01-11 09:40:39)
tak na szybko. Zmodyfikowana funkcja. Dla kilku tabel na stronie źle się przypisywały indeksy kolumn i sortowanie działało tylko dla jednej tabeli.
function attachSorting(){
var handlers=[['SSort', ValueSort],['ISort',IntegerSort]];

for(var j=0, ttt=document.getElementsByTagName('table');tt=ttt[j];j++){
for(var i=0, ths=tt.getElementsByTagName('th'); th=ths[i]; i++){
for (var h=0; h<handlers.length;h++) {
if(Contains(th.className.split(" "), handlers[h][0])){
th.columnIndex=i;
th.order=-1;
th.sortHandler = handlers[h][1];
th.onclick=function(){sort(this);}
var divNode = document.createElement('div');
var textNode = document.createTextNode('');
divNode.appendChild(textNode);
th.appendChild(divNode);
th.sortTextNode = textNode;
}}}}}
zainteresowany (2018-05-16 12:04:50)
A jak załatwić sprawę z polskimi znakami oraz przy okazji z niezmieniającą się wartością pierwszej kolumny będąca np. liczbą porządkową? ma ktoś jakiś pomysł?
Dodaj komentarz
Wyślij
Ostatnie komentarze
bardo ciekawe , można dzięki takim wpisom dostrzec wędkę..
Bardzo dziękuję za jasne tłumaczenie z dobrze dobranym przykładem!
Dzieki za te informacje. były kluczowe
Dobrze wyjaśnione, dzięki !