Sortowanie tabeli w HTML i JavaScript - cz.2
...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.
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:
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:
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:
.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.
<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:
Integer | String | Domyślne | Inne |
---|---|---|---|
2 | A | 2 | Dodatkowe dane 1 |
10 | B | 10 | Dodatkowe dane 2 |
3 | G | 3 | Dodatkowe dane 3 |
111 | D | 111 | Dodatkowe 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
Komentarze:
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ę.
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;
}}}}}
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.