Das echte SELFHTML-Wiki gibt es unter https://wiki.selfhtml.org.
JavaScript/Tutorials/Tabellen dynamisch sortieren
Bei tabellarischen Daten muss schon beim Erstellen der Tabelle festgelegt werden, in welcher Sortierung die Daten dargestellt werden sollen. Soll durch eine Benutzeraktion die Reihenfolge geändert werden, benötigen Sie bei statischem HTML für jede Sortierung ein eigenes HTML-Dokument, bei dynamisch aus z.B. einer Datenbank erstellten Tabellen können die Daten serverseitig umsortiert werden.
Diese Sortierung kann aber auch mittels Javascript ohne Serverunterstützung im Browser durchgeführt werden. Dieser Artikel beschreibt, wie dabei vorzugehen ist.
Inhaltsverzeichnis
Die Tabelle im HTML
Der folgende HTML-Code zeigt eine Tabelle mit fünf Spalten. Die Tabelle soll nach jeder dieser Spalten durch einen Klick auf die entsprechende Spaltenüberschrift sortiert werden. Über das class-Attribut wird dem Script mitgeteilt, dass diese Tabelle sortierbar sein soll. Beachten Sie, dass an dieser Stelle ausschließlich das HTML vorgestellt wird, die Tabelle also noch nicht sortierbar ist. Wie dies umzusetzen ist, lernen Sie im weiteren Verlauf dieses Artikels.
<table class="sortierbar">
<thead>
<tr>
<th>Lfd. Nr.</th>
<th>Name</th>
<th>Punkte</th>
<th>Note</th>
<th>Bemerkung</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Matthias</td>
<td>9</td>
<td>2.5</td>
<td>Normal</td>
</tr>
<tr>
<td>2</td>
<td>Gunnar</td>
<td>12</td>
<td>1.2</td>
<td><b>Fett</b></td>
</tr>
<tr>
<td>3</td>
<td>Christian</td>
<td>8</td>
<td>3.5</td>
<td><i>Kursiv</i></td>
</tr>
<tr>
<td>4</td>
<td>Janosch</td>
<td>11</td>
<td>1,4</td>
<td><a href="#">Link</a></td>
</tr>
<tr>
<td>5</td>
<td>Raoul</td>
<td>10</td>
<td>2.1</td>
<td><b><a href="#">Fetter Link</a></b></td>
</tr>
<tr>
<td>6</td>
<td>Jürgen</td>
<td>7</td>
<td>3.9</td>
<td><h2>Überschrift</h2></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan=5>Stand: 1. 11. 15</td>
</tr>
</tfoot>
</table>
Das Javascript
Zuerst muss das Script die zu sortierenden Tabellen finden. Dieses erfolgt mit der Methode querySelectorAll. Danach wird für jede Tabelle das Objekt tableSort angelegt. Damit sichergestellt ist, dass die Tabelle auch schon angelegt ist, wird die Suche in die Funktion initTableSort gelegt und mit addEventListener als Eventlistener zum Event DOMContentLoaded hinzugefügt.
var tableSort = function (tab) {
} // tableSort
var initTableSort = function () {
var sort_Table = document.querySelectorAll("table.sortierbar");
for (var i = 0; i < sort_Table.length; i++) new tableSort(sort_Table[i]);
} // initTableSort
window.addEventListener("DOMContentLoaded",initTableSort,false);
Die Sortierung soll durch einen Klick auf die Spaltenüberschrift ausgelöst werden. Dazu könnte man den th-Felder im thead-Bereich der Tabelle einen Eventhandler für das click-Event geben. Dann wäre aber der Sortierer mit der Tastatur nicht zu bedienen. Daher setzen wir in die th-Felder einen Button mit deren Inhalt und deren Aussehen. Diesem Button geben wir dann den Eventhandler für das click-Event:
var titel = tab.getElementsByTagName("thead")[0].getElementsByTagName("tr")[0].getElementsByTagName("th");
var sortbuttonStyle = document.createElement("style"); // Stylesheet für Button im TH
sortbuttonStyle.innerText = ".sortbutton { width:100%; height:100%; border: none; background-color: transparent; font: inherit; color: inherit; text-align: inherit; padding: 0; cursor: pointer; } .sortbutton::-moz-focus-inner { margin: -1px; border-width: 1px; padding: 0; }";
document.head.appendChild(sortbuttonStyle);
var initTableHead = function (sp) { // Kopfzeile vorbereiten
var b = document.createElement("button");
b.type = "button";
b.className = "sortbutton";
b.innerHTML = titel[sp].innerHTML;
b.addEventListener("click",function () { tsort(sp); }, false);
titel[sp].innerHTML = "";
titel[sp].appendChild(b);
}
for (var i = 0; i < titel.length; i++) initTableHead(i) ;
Zum Sortieren wird die Arraymethode sort verwendet. Dazu muss der Inhalt der HTML-Tabelle in ein 2D-Array kopiert werden. Zusätzlich wird auch noch die Referenz auf die Tabellenzeile in das Array kopiert. Ein 2D-Array kann man als 1D-Array ansehen, dessen Elemente wieder 1D-Arrays sind:
var arr = new Array(nzeilen);
for (var z = 0; z < nzeilen; z++) arr[z] = new Array(nspalten);
Der Zugriff auf die Tabellenzeilen erfolgt über die Methode rowsdes TableObjects:
var tbdy = tab.getElementsByTagName("tbody")[0];
var tz = tbdy.rows;
var nzeilen = tz.length;
if (nzeilen == 0) return;
var nspalten = tz[0].cells.length;
var arr = new Array(nzeilen);
for (var z = 0; z < nzeilen; z++) {
var zelle = tz[z].getElementsByTagName("td"); // cells;
arr[z] = new Array(nspalten+1);
arr[z][nspalten] = tz[z];
for (var s = 0; s < nspalten; s++) {
var zi = getData(zelle[s]);
arr[z][s] = zi ;
}
}
Das Auslesen der Tabellenfelder erfolgt in der Funktion:
var getData = function (ele) {
return ele.innerHTML;
}
Zum Sortieren wird die Array-Methode sort verwendet. Da ein 2D-Array sortiert werden soll, müssen in der Vergleichsfunktion der Methode sort die Werte aus den Zeilen-Arrays miteinander verglichen werden, die zur Spalte gehören, nach der sortiert werden soll:
var vglFkt = function (a, b) {
var as = a[sortiert], bs = b[sortiert];
if (as > bs) return 1;
else return -1;
}
In der Sortierfunktion tsort wird dann nur noch überprüft, ob die Tabelle schon nach der gewünschten Spalte sortiert wurde, dann wird mit der Array-Methode reverse nur die Reihenfolge umgedreht, sonst wird sortiert und gespeichert, nach welcher Spalte sortiert wurde:
var tsort = function (sp) {
if (sp == sortiert) arr.reverse(); // Tabelle ist schon nach dieser Spalte sortiert, also nur Reihenfolge umdrehen
else { // Sortieren
sortiert = sp;
arr.sort(vglFkt);
}
for (var z = 0; z < nzeilen; z++) tbdy.appendChild(arr[z][nspalten]); // Sortierte Daten zurückschreiben
}
Das vollständige Script sieht jetzt so aus:
( function () {
"use strict";
var tableSort = function (tab) {
var titel = tab.getElementsByTagName("thead")[0].getElementsByTagName("tr")[0].getElementsByTagName("th");
var tbdy = tab.getElementsByTagName("tbody")[0];
var tz = tbdy.rows;
var nzeilen = tz.length;
if (nzeilen == 0) return;
var nspalten = tz[0].cells.length;
var arr = new Array(nzeilen);
var sortiert = -1;
var sortbuttonStyle = document.createElement("style"); // Stylesheet für Button im TH
sortbuttonStyle.innerText = ".sortbutton { width:100%; height:100%; border: none; background-color: transparent; font: inherit; color: inherit; text-align: inherit; padding: 0; cursor: pointer; } .sortbutton::-moz-focus-inner { margin: -1px; border-width: 1px; padding: 0; }";
document.head.appendChild(sortbuttonStyle);
var initTableHead = function (sp) { // Kopfzeile vorbereiten
var b = document.createElement("button");
b.type = "button";
b.className = "sortbutton";
b.innerHTML = titel[sp].innerHTML;
b.addEventListener("click", function () { tsort(sp); },false);
titel[sp].innerHTML = "";
titel[sp].appendChild(b);
}
var getData = function (ele) {
return ele.innerHTML;
}
var vglFkt_s = function (a, b) {
var as = a[sortiert], bs = b[sortiert];
if (as > bs) return 1;
else return -1;
} // vglFkt_s
var tsort = function (sp) {
if (sp == sortiert) arr.reverse(); // Tabelle ist schon nach dieser Spalte sortiert, also nur Reihenfolge umdrehen
else { // Sortieren
sortiert = sp;
arr.sort(vglFkt_s);
}
for (var z = 0; z < nzeilen; z++) tbdy.appendChild(arr[z][nspalten]); // Sortierte Daten zurückschreiben
} // tsort
// Kopfzeile vorbereiten
for (var i = 0; i < titel.length; i++) initTableHead(i) ;
// Tabelleninhalt in ein Array kopieren
for (var z = 0; z < nzeilen; z++) {
var zelle = tz[z].getElementsByTagName("td"); // cells;
arr[z] = new Array(nspalten +1);
arr[z][nspalten] = tz[z];
for (var s = 0; s < nspalten; s++) {
var zi = getData(zelle[s]);
arr[z][s] = zi ;
// zelle[s].innerHTML += "<br>" +zi; // zum Debuggen
}
}
} // tableSort
var initTableSort = function () {
var sort_Table = document.querySelectorAll("table.sortierbar");
for (var i = 0; i < sort_Table.length;i++) new tableSort(sort_Table[i]);
} // initTable
if (window.addEventListener) window.addEventListener("DOMContentLoaded", initTableSort, false); // nicht im IE8
})();
Dabei werden beim Zurückschreiben nicht die Tabellenfelder einzeln zurückkopiert. Statt dessen werden die Tabellenzeilen, deren Referenzen ja auch in das 2D-Array geschrieben wurden, einfach in der neuen Reihenfolge mit appendChild in den tbody eingehängt.
Das Sortieren nach den ersten beiden Spalten funktioniert, aber bei der dritten und vierten Spalte versagt der Algorithmus. Das liegt daran, dass die Methode innerHTML den Inhalt der Tabellenzellen als String liest. Daher werden die Zahlen als Buchstabenfolge sortiert und 10 ist so kleiner als 9. Es muss also beim Lesen der Tabellenfelder geprüft werden, ob eine Zahl oder ein String vorliegt. Die modifizierte Funktion getData sieht jetzt so aus:
var getData = function (ele, s) {
var val = ele.innerHTML;
if (!isNaN(val) && val.search(/[0-9]/) != -1) return val;
var n = val.replace(",", ".");
if (!isNaN(n) && n.search(/[0-9]/) != -1) return n;
sorttype[s] = "s"; // String
return val;
} // getData
Mit dieser Erweiterung können jetzt Zahlen oder Texte sortiert werden, sobald sich in den Tabellenzellen aber HTML-Elemente befinden, wie im Beispiel in der rechten Spalte, funktioniert das Sortieren noch nicht richtig. Dieses liegt daran, das wir zum Auslesen die Methode innerHTML verwenden. Hier werden die Tags mit in die Sortierung einbezogen. Wenn wir innerHTML durch textContent ersetzen, wird nur noch der Inhalt der Elemente ohne die Tags ausgelesen:
var getData = function (ele, s) {
var val = ele.textContent;
if (!isNaN(val) && val.search(/[0-9]/) != -1) return val;
var n = val.replace(",", ".");
if (!isNaN(n) && n.search(/[0-9]/) != -1) return n;
sorttype[s] = "s"; // String
return val;
} // getData
Fazit
Dieser Tabellensortierer liefert in vielen Fällen schon zufriedenstellende Ergebnisse. Allerdings sind z.B. Umlaute oder Datums- und Zeitangaben noch nicht berücksichtigt. Auch können Sie noch nicht wählen, nach welchen Spalten sortiert werden soll. Einen deutlich umfangreicheren Tabellensortierer finden Sie unter http://www.j-berkemeier.de/TableSort.html.
Weblinks
- j-berkemeier.de: TableSort