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ł?
Devil8 (2020-07-20 14:29:23)
Przydałyby się jeszcze 2 rzeczy do cz. 3 i byłoby superanckie.
1. Na starcie sortuje wg jakiejś kolumny i tam jest już strzałeczka. Widok takiej strzałeczki daje znać użytkownikowi, że taką tabele można sortować, a na razie pojawia się ona tylko po kliknięciu.
2. Uwzględnienie polskich znaków, bo np. przy sortowaniu Nazwisk i Imion jest to bardzo uciążliwe.
Ogólnie bardzo fajnie i prosto.
PS. Jest ten artykuł z jQuery już dostępny.
Dodaj komentarz
Wyślij
Ostatnie komentarze
Świetny artyk€ł !
Ooo chyba użyli varchar-a ;)
Morzna by bylo trohe jasiniej?
To samo pytanie co wyżej. Mam za zadanie dodać kolumnę do istniejącej tabeli łącząc obie inne kolumny ze sobą, ale nie mam pojęcia jak za to się zabrać
działa :) tylko była literówka :)
Podziękował. Trochę późno, po 8 latach, ale dzięki za testy (rozumiem że dla SQL2012 robione). Tak się właśnie zastanawiałem ile złego czynię stosując czasem __(max).