Anzeige
Tutorialbeschreibung

Praxisfälle für JavaScript/DOM - Interaktive Tabellensortierung

Praxisfälle für JavaScript/DOM - Interaktive Tabellensortierung

In Kapitel 7 wurden zwar schon diverse für die Praxis nützliche Scripts vorgestellt, dochdie Beispiele hatten dort unterstützenden Charakter, um bestimmte Sprachkonzepte zuerläutern. In diesem Kapitel sollen die Beispiele im Vordergrund stehen. Das Kapitel zeigt,wie praxistypische Scripts entstehen und was dabei berücksichtigt werden sollte.Wir konzentrieren uns auf drei wirklich nützliche Anwendungen, die JavaScript auch fürprofessionelle Seiten salonfähig macht. Das Kapitel hat Workshop-Charakter.
 


Das nun folgende Tutorial ist ein Auszug aus dem Buch: Professionelle Websites von Stefan Münz.
Die Veröffentlichung des Kapitels erfolgt mit freundlicher Genehmigung von Pearson Education.

3 Interaktive Tabellensortierung

Es gibt zahlreiche Informationen, die sich am besten in einer Tabelle darstellen lassen. In HTML müssen Sie sich dabei entscheiden, nach welchem Kriterium Sie die Tabellendaten sortieren, oder Sie verzichten ganz auf eine Sortierung.

Gerade bei größeren Tabellen wünscht sich mancher Anwender jedoch, die Tabellenzeilen nach bestimmten Spalten sortieren zu können. Das steigert die Informationsauswertung. Gewöhnt sind die Anwender das Feature aus zahlreichen Desktop- und Internetanwendungen, etwa aus E-Mail- Programmen, wo sich Nachrichtenlisten wahlweise nach Absender, Eingangsdatum usw. sortieren lassen.

Auf Webseiten sucht man diese Möglichkeit dagegen meist vergebens. Dabei ist gerade die Möglichkeit, größere Tabellen dynamisch zu sortieren, eine der interessantesten und Interaktive nützlichsten Anwendungen für JavaScript. Mit diesem Beispiel möchten wir ein Script vorstellen, das wiederverwendbar eingesetzt werden kann und mit dessen Hilfe Webseiten mit tabellarischen Informationen eine echte Aufwertung erfahren.

3.1 Das Beispiel

Bilder

Abbildung 8.3: Tabelle im HTML-Originalzustand

Die abgebildete Tabelle ist durch Anklicken der Spaltenüberschriften nach der angeklickten Spalte sortierbar:

Bilder

Abbildung 8.4: Tabelle nach letzter Spalte absteigend sortiert

Eine kleine Grafik vor der Spaltenüberschrift der Sortierspalte zeigt an, nach welcher Spalte die Tabelle aktuell sortiert ist, und zwar, ob absteigend oder aufsteigend. Es kann sowohl alphanumerisch als auch numerisch sortiert werden.
Unser Beispielscript kann beliebige Tabellen mit definierten Spalten verarbeiten, auch mehrere unterschiedliche auf einer Seite.

3.2 Quelltexte und Erläuterungen

Zunächst der Quelltext des HTML-Dokuments mit der zu sortierenden Tabelle. Das Java- Script haben wir in eine externe Datei ausgelagert.

Listing 8.5: HTML-Datei mit Tabelle zum Sortieren
Bilder

Eine Tabelle, welche mit unserem Beispielscript sortiert werden soll, muss im einleitenden <table>- Tag mit id= einen id-Namen erhalten. Weiterhin muss sie unterhalb des <table>- Tags mithilfe eines colgroup-Elements alle Spalten der Tabelle in col-Elementen vordefinieren. Die col-Elemente sind auch der beste Ort, um die gewünschten Spaltenbreiten vorzugeben. Daneben muss die zu sortierende Tabelle zumindest die Bereiche <thead> ... </thead> und <tbody> ... </tbody> explizit durch diese Tags markiert enthalten.

Der Inhalt des thead-Elements besteht aus einer Tabellenzeile mit den Spaltenüberschriften. In unserem Beispiel haben wir es so gelöst, dass der Inhalt der Kopfzellen jeweils aus einem anklickbaren Button (<button> ... </button>) besteht. Mit dem Selektor th button wird im zentralen Style-Bereich für solche Buttons unter anderem festgelegt, dass sie 100% der verfügbaren Breite einnehmen sollen. So erreichen wir, dass die Buttons die gesamte Tabellenzelle einnehmen. Jedes button-Element enthält einen Event-Handler onclick=, der beim Anklicken dafür sorgt, dass die Tabelle sortiert wird. Dazu später noch mehr.

Der Elementinhalt jedes Buttons besteht aus einem leeren span-Element und der Spaltenüberschrift. Das span-Element ist der Behälter für die kleinen Grafiken, welche in der Sortierspalte erscheinen und auf- oder absteigende Sortierung anzeigen. Jedes dieser span- Elemente muss einen id-Namen erhalten, der folgender Konvention genügen muss: Er beginnt mit dem id-Namen der Tabelle, gefolgt von _sort_img_ und einer Laufnummer. Die erste Spalte bekommt eine 0, die zweite eine 1, die dritte eine 2 usw. Diese Konvention ist für das Script wichtig, um die Grafiken korrekt zu platzieren.

Ansonsten sind keine weiteren Konventionen erforderlich. Die Tabellendaten können wie üblich notiert werden.
Das Script, das die Tabelle sortiert, ist über ein script-Element in den Kopfdaten des HTMLDokuments als externe Datei namens tabsort.js eingebunden. Sein Quelltext lautet:

Listing 8.6: JavaScript für HTML-Tabellensortierung
Bilder


Zu Beginn des Scripts werden einige globale Variablen deklariert und initialisiert. Mit default_order kann festgelegt werden, ob eine Tabelle beim ersten Anklicken einer Spalte nach deren Werten zunächst aufsteigend (asc) oder absteigend (desc) sortiert werden soll. Danach wird bei jedem weiteren Klick automatisch umgeschaltet. Die beiden URIs der Grafiken, die aufsteigende und absteigende Sortierung signalisieren, lassen sich natürlich anpassen, ebenso wie die zugehörigen Alternativtexte.

Die Variable delimiter verdient besondere Aufmerksamkeit. Die zugewiesene Zeichenkette, im Beispiel fünf Senkrechtstriche, darf innerhalb der Tabelle nicht in den Daten vorkommen. Das Script benötigt diese Variable, um einen Tabellenzeilen-Array temporär zu einem String zusammenzusetzen und diesen anhand des Begrenzers (Delimiter) anschließend wieder in seine Einzelwerte zerlegen zu können.

Ferner wird beim Einlesen des Scripts ein Array namens tables angelegt sowie eine Array- Zählervariable ti. Alle übrigen Anweisungen des Scripts stehen innerhalb von Funktionen und werden daher erst bei Aufruf der Funktionen ausgeführt. Insgesamt kommen folgende Funktionen vor:

- sort_table(): Diese Funktion dient zur Erstellung eines Objekts. Das Script legt für jede zu sortierende Tabelle eine Instanz dieses Objekts an und speichert es im zuvor deklarierten Array tables. Auf diese Weise wird, falls mehrere sortierbare Tabellen auf einer Seite vorkommen, eine saubere Datenhaltung erreicht.
- init_tabsort(): Diese Funktion initialisiert die Sortierbarkeit einer Tabelle. Aufgerufen werden muss sie, bevor der Anwender einen Sortiervorgang anstößt. Der richtige Ort, um diese Funktion aufzurufen, ist der Event-Handler onload= im einleitenden <body>-Tag. Für jede sortierbare Tabelle auf einer Seite muss diese Funktion aufgerufen werden. Dabei muss ihr der id-Name der zu sortierenden Tabelle als Parameter übergeben werden.
- get_sort_table_obj_by_id(): Dies ist eine Hilfsfunktion des Script, mit deren Hilfe eine Anweisung schnell ein im Array tables gespeichertes Objekt des Typs sort_table auffinden kann.
- numsort(): Diese Hilfsfunktion wird benötigt, um bei Anwendung der sort()-Methode des Array- Objekts eine numerische Sortierung zu ermöglichen.
- tabsort(): Diese Funktion führt die eigentliche Sortierung durch. Sie wird über den Event-Handler onclick= beim Anklicken der Buttons in den Tabellenüberschriften aufgerufen.

Die beiden »großen« Funktionen sind also init_tabsort() und tabsort(). In init_tabsort() wird, nachdem alle nicht-DOM-fähigen Browser wieder heimgeschickt wurden, in der Array-Variablen tables[ti] ein neues Objekt des Typs sort_table gespeichert. Dazu wird die Objektfunktion sort_table() aufgerufen.

Das sort_table-Objekt hat unter anderem eine Eigenschaft obj. In dieser wird das DOMObjekt der gesamten Tabelle gespeichert, indem document.getElementById(table_id) an tables[t].obj zugewiesen wird. Über tables[t].obj ist dadurch innerhalb der Funktion fortan der DOM-Zugriff auf die Tabelle möglich.

Im weiteren Verlauf analysiert init_tabsort() die Tabelle. Nun wird auch klar, warum die Tabelle in HTML ein paar Konventionen einhalten muss, die bereits beschrieben wurden. Das colgroup-Element wird gesucht und die Anzahl der Spalten wird ermittelt. Der gesamte Tabellenkörper, identifizierbar am tbody-Element, wird als Objekt in der Objekteigenschaft tables[t].tbody_obj gespeichert.

In der größeren, verschachtelten for-Schleife im zweiten Teil von init_tabsort() passiert Folgendes: jedes tr- und jedes td-Element erhält einen eindeutigen id-Namen, damit später ein möglichst einfacher Zugriff darauf möglich ist. Die id-Namensvergabe folgt dabei einem bestimmten Schema.

Betrachten wir folgenden HTML-Ausschnitt:

<tr>
<td>Buttermilch</td>
<td>Milch und Milchprodukte</td>
<td class="fp">1</td>
</tr>
<tr>
<td>Fruchtjoghurt 1,5% 150g</td>
<td>Milch und Milchprodukte</td>
<td class="fp">2</td>
</tr>

Daraus macht init_tabsort() im Arbeitsspeicher folgenden Code:

<tr id="tr_0">
<td id="tr_0_td_0">Buttermilch</td>
<td id="tr_0_td_1">Milch und Milchprodukte</td>
<td id="tr_0_td_2" class="fp">1</td>
</tr>
<tr id="tr_1">
<td id="tr_1_td_0">Fruchtjoghurt 1,5% 150g</td>
<td id="tr_1_td_1">Milch und Milchprodukte</td>
<td id="tr_1_td_2" class="fp">2</td>
</tr>

Die tr-Elemente des sortierbaren Tabellenkörpers werden also mit tr_0, tr_1, tr_2 usw. »nummeriert«. Innerhalb einer Tabellenzeile erhalten alle td-Elemente den tr-Namen als vorderen id-Namensteil. Angehängt wird dann für jede Spalte _td_0 für die erste Spalte, _td_1 für die zweite Spalte, _td_2 für die dritte usw. Der anfängliche DOM-Zugriff auf die Tabellenzeilen und -zellen ist etwas komplex. Greifen wir zum besseren Verständnis die folgende if-Abfrage heraus:

if(tables[t].tbody_obj.childNodes[i].childNodes[j].nodeName.toLowerCase() ==
'td')

Wie weiter oben bereits erwähnt, ist in tables[t].tbody_obj der tbody-Elementknoten der sortierbaren Tabelle gespeichert. Über tables[t].tbody_obj.childNodes ist der DOMZugriff auf alle Kindknoten dieses Elementknotens möglich. Dazu gehören neben anderen Knoten auch die Elementknoten der inneren tr-Elemente. In der herausgegriffenen if- Abfrage, die innerhalb einer for-Schleife steht, ist in childNodes[i] ein tr-Element ermittelt worden. Die Abfrage sucht jedoch nach td-Elementen. Also muss sie noch weiter in der Hierarchie herabsteigen und abermals nach childNodes suchen, diesmal nach denen des tr- Elements. Die if-Abfrage steht nicht nur innerhalb einer for-Schleife, sondern innerhalb einer zweiten. In childNodes[j] (j ist der Schleifenzähler der inneren for-Schleife, i derjenige der äußeren!) ist ein aktueller Kindknoten des tr-Elements (also des Elementknotens tbody_obj.childNodes[i]) gespeichert. Über die Objekteigenschaft nodeName wird der Knotenname ermittelt. Durch Anwendung von toLowerCase() wird dieser Wert klein geschrieben interpretiert. Wenn das Kindobjekt td heißt, dann ist die if-Bedingung erfüllt.

Nachdem die Funktion init_tabsort() beendet wurde, kann die betroffene Tabelle nach jeder ihrer Spalten auf- und absteigend, alphanumerisch oder numerisch sortiert werden. Angestoßen wird die Sortierung im Beispiel wie schon angedeutet über onclick-Event- Handler in den button-Elementen der Spaltenüberschriften. Den onclick-Event-Handlern wird dabei als Wert ein Aufruf der Funktion tabsort() zugewiesen. Die Funktion erwartet drei Parameter. Als erster Parameter muss der id-Name der Tabelle übergeben werden – in unserem Beispiel lautet er fettpunkttabelle. Als zweiter Parameter wird entweder an oder n übergeben. Mit an wird eine alphanumerische Sortierung angewiesen und mit n eine numerische. In unserem Beispiel enthält die dritte Spalte nur Zahlenwerte. Damit diese wie gewünscht sortiert werden, wird für diese Spalte eine numerische Sortierung angewiesen. Die beiden anderen Spalten enthalten Zeichenketten als Werte, daher wird für sie an übergeben. Als dritter Parameter muss schließlich noch die Indexnummer der zu sortierenden Spalte übergeben werden. Bei der ersten Spalte ist dies 0, bei der zweiten 1, bei der dritten 2 usw.

In tabsort() wird über die Funktion get_sort_table_obj_by_id() das im Array tables gespeicherte sort_table-Objekt der betroffenen Tabelle geholt und in der Variablen to gespeichert. Über to ist damit der Zugriff auf das sort_table-Objekt der Tabelle und damit auch auf die darin gespeicherten Objekte der Tabelle selbst möglich.

Als Nächstes wird ein Array namens sort_array erzeugt. Was innerhalb der anschließenden for- Schleife passiert, ist Folgendes: Für jede Tabellenzeile des sortierbaren Tabellenkörpers werden die einzelnen Werte aus den Zellen dieser Zeile geholt. Aus den Werten wird eine Zeichenkette zusammengesetzt, die in der Variablen tr_str gespeichert wird. Zwischen den Werten der Zellinhalte wird jeweils die Zeichenfolge eingefügt, die in der globalen Variable delimiter gespeichert ist. Das ist auch der Grund, warum diese Zeichenfolge in den Tabellendaten selbst nicht vorkommen darf.

Angenommen, folgende HTML-Tabellenzeile wird verarbeitet:

<tr>
<td>Buttermilch</td>
<td>Milch und Milchprodukte</td>
<td class="fp">1</td>
</tr>

Daraus wird nach dem oben Beschriebenen in unserem Beispiel folgende Zeichenkette:

Buttermilch|||||Milch und Milchprodukte|||||1

Nun soll die so erzeugte Zeichenkette den Zweck erfüllen, in sort_array als Wert übernommen zu werden. Am Ende steht jede Tabellenzeile in dieser Form in sort_array. Durch Aufruf der sort()- Methode für Arrays werden die Werte sortiert. Wenn nun beispielsweise nach der dritten Spalte sortiert werden soll, müssen deren Werte aber vorne stehen, damit die Sortiermethode greift. Deshalb wird in tr_str der Tabellenzeileninhalt nicht einfach nur »der Reihe nach« gespeichert, sondern in der Reihe, die für die gewünschte Sortierung tauglich ist. Wird also beispielsweise eine Sortierung nach Spalte 3 gewünscht, wird Folgendes in tr_str erzeugt:

1|||||Buttermilch|||||Milch und Milchprodukte

Im Anschluss an die for-Schleife wird innerhalb von tabsort() der so erzeugte Array sort_array() durch Aufruf der Standard-Array-Methode sort() sortiert. Falls eine absteigende Sortierung gewünscht ist, muss außerdem noch reverse() angewendet werden, was die Elementreihenfolge im Array einfach umkehrt und ebenfalls eine Standard- Array-Methode ist. Falls eine numerische Sortierung gewünscht ist, wird der sort()-Methode der Name der Hilfsfunktion numsort übergeben. Diese erzwingt eine Interpretation von zwei zu vergleichenden Werten als Fließkommazahl und bedient die sort()-Methode so, wie sie es benötigt.

Nach erfolgreicher Sortierung muss sort_array nun wieder verarbeitet werden. Jedes Array-Element stellt ja eine Tabellenzeile dar, mittlerweile jedoch sortiert. In einer for- Schleife wird der Array abgearbeitet Mithilfe der split()-Methode wird die aktuelle Zeile anhand der Delimiter-Zeichenfolge wieder in Array-Elemente zerlegt (tr_array). Die Werte können nun direkt in die Tabelle geschrieben werden. Dabei kann bequem über die von der Funktion tabsort_init() erzeugten id- Namen auf die einzelnen Tabellenzellen zugegriffen werden. Jede Tabellenzelle erhält mit innerHTML einen neuen Wert, der sich durch die Sortierung ergibt.

Fazit
Das Beispiel ist nur eines dafür, was bei HTML-Tabellen in Verbindung mit DOM und JavaScript möglich ist. Tabellensortierung bringt dem Anwender einen eindeutigen informativen Mehrwert. Mit etwas Phantasie ist mit den gleichen Bordmitteln jedoch noch viel mehr möglich. Angenommen, jede Tabellenzelle besteht aus einem input-Eingabefeld (dieses kann ja mit CSS (border:none) rahmenlos gemacht werden, damit es nicht so »formularmäßig « aussieht). Auf diese Weise entsteht eine vollständig editierbare Tabelle. Mit etwas JavaScript/DOM können Sie dann Ansätze einer richtigen Tabellenkalkulation auf Ihrer Webseite realisieren.


 

Das Tutorial ist ein Auszug aus dem Buch von Stefan Münz:

Professionelle Websites - Programmierung, Design und Administration von Webseiten
Addison-Wesley, 2. Auflage, 1136 Seiten, gebunden, komplett in Farbe, mit DVD

Die Veröffentlichung des Kapitels erfolgt mit freundlicher Genehmigung von
Pearson Education.

Mehr Informationen zu diesem wunderbaren Fachbuch für Webmaster und Webentwickler
gibt es hier: Professionelle Websites

Alle Teile des Buches: 

1 Intro
2 HTML und CSS
3 Dynamische Seiten mit JavaScript/DOM
4 Die Server-Seite
5 PHP und MySQL
6 XML
7 Betrieb von Websites
8 Referenz
Bilder

DVD-Werbung
Kommentare
Achtung: Du kannst den Inhalt erst nach dem Login kommentieren.
Portrait von MaoMao
  • 09.01.2013 - 16:58

Gute Tutorial leicht erklärt.

x
×
×