Tree List: Grundlagen
Zurück: Demo-Übersicht
1. Übersicht und Zweck
Status: [Live].
Quelle: lib/plugins/wkfluentui/helper/widgets.php, Methode
treeList(). Baut auf dem Kontrakt von
dataGrid() auf,
statt ihn zu duplizieren.
2. Voraussetzungen
dataGrid()-
Basiskontrakt bereits verstanden — Tree List erbt $columns
(key/label/align/mono/width) und die Zellen-Konvention
(Klartext escaped, ['html' => …] Aufrufer-escaped) unverändert.
3. Konzepte
Ein Grid, hierarchische Zeilen: der einzige strukturelle Unterschied zu
dataGrid() liegt in $rows — Zeilen können verschachtelte
Kind-Zeilen tragen (rekursiv, wie bei tree()-children).
4. Erste Schritte
$rows = [ [ 'id' => 1, 'name' => 'de', 'size' => '', 'children' => [ ['id' => 2, 'name' => 'wiki', 'size' => ''], ['id' => 3, 'name' => 'blog', 'size' => ''], ], ], ['id' => 4, 'name' => 'en', 'size' => ''], ]; echo $widgets->treeList($columns, $rows, [ 'rowKey' => 'id', 'childrenKey' => 'children', ]);
5. Verwendung
Steht zwischen DataGrid (viele gleichartige Zeilen, flach) und TreeView (Hierarchie, aber nur eine Spalte) — für hierarchische Daten mit mehreren Spalten (z. B. Dateisystem-Explorer mit Größen-/Datums-Spalten).
6. API-Referenz
treeList(array $columns, array $rows, array $opts = []): string in
helper_plugin_wkfluentui_widgets. Leerer String bei leerem
$columns; leere $rows rendern Kopfzeile + Leer-Zustandszeile
(empty-Text).
7. Parameter, Optionen und Zustände
| Schlüssel | Typ | Bedeutung |
|---|---|---|
rowKey | string | Spalten-Key mit dem eindeutigen Zeilenwert — Pflicht für expanded/expandUrl/selection |
childrenKey | string | Schlüssel in $rows, unter dem Kind-Zeilen liegen (rekursiv, wie bei tree()-children), Default children |
expanded | array von rowKey-Werten | initial aufgeklappte Elternzeilen; ohne Angabe sind alle Elternzeilen zugeklappt |
expandUrl | callable (string $key, bool $expand): string | No-JS-Toggle-Link je Elternzeile; die Pseudo-Keys *all/*none liefern die URLs der „Alle auf-/zuklappen„-Toolbar — Expand/Collapse |
maxDepthIndent | int (Default 6) | Einrückungsgrenze — Adaptivity |
selection | 'none'|'multi' | Checkbox-Spalte (selection[] im Aufrufer-Formular, wie dataGrid()); erfordert rowKey |
rowActions | callable | Aktions-Zelle je Zeile (wie dataGrid()) |
empty, ariaLabel | string | wie dataGrid() |
Erzeugtes Markup
Ein einziges natives <table role="treegrid"> (dieselbe
Begründung wie bei dataGrid(): getrennte Teilbäume desynchronisieren
Spaltenbreiten) — jede Zeile trägt data-wk-depth="<n>" plus
aria-level/aria-setsize/aria-posinset, Elternzeilen zusätzlich
data-wk-expanded="true|false" und aria-expanded. Die
Einrückung der ersten Spalte ist ein serverseitiger Inline-Stil (15 px je
Ebene, gedeckelt durch maxDepthIndent).
Render-Grenze (verbindlich): Kind-Zeilen einer zugeklappten
Elternzeile rendern nicht ins DOM (nicht nur hidden) — bei sehr
tiefen Bäumen bliebe sonst dieselbe Render-Grenze wie bei fehlender
Virtualisierung im
DataGrid
bestehen, nur unsichtbar statt vermieden.
8. Vollständige Beispiele
Siehe Abschnitt 4 plus Expand/Collapse
für das expandUrl-Zusammenspiel.
9. Einschränkungen und Randfälle
- Keine Sortierung, kein Filter, kein Paging — die Hierarchie-Reihenfolge ist maßgeblich; wer flach sortieren/filtern will, nutzt
dataGrid(). - Erbt die dataGrid()-Grenzen: kein virtuelles Scrollen, keine editierbaren Zellen (dafür
declarativeTable()).
10. Accessibility und Kompatibilität
Vollständiger Überblick: Accessibility.
11. Troubleshooting
Symptom: Elternzeile zeigt kein Toggle-Dreieck als Link.
Ursache: expandUrl fehlt oder die Zeile hat keinen rowKey-Wert
— ohne beides rendert nur ein statisches Dreieck.
Lösung: rowKey + expandUrl setzen (Abschnitt 7).
12. Verwandte Themen
- Demo-Übersicht — alle Kategorien
- DataGrid: Grundlagen — geerbter Basiskontrakt
- TreeView: Grundlagen — verwandte Hierarchie-Idee ohne Spalten
Verzögertes Nachladen eines Teilbaums
Diese beiden Schlüssel stehen je Zeile, nicht in $opts:
| Schlüssel | Typ | Bedeutung |
|---|---|---|
lazy | bool | Die Zeile hat Kinder, trägt sie aber nicht. Sie rendert trotzdem als aufklappbarer Elternknoten. |
lazyUrl | string | Adresse, von der scripts/treelist.js den Teilbaum beim ersten Aufklappen holt. |
Was das spart, liegt auf dem Server, nicht im Browser. treeList() rendert eingeklappte
Kinder ohnehin nicht ins DOM — der Aufrufer musste sie bislang aber trotzdem alle aufbauen,
weil die Methode über $row[$childrenKey] läuft. Mit lazy entfällt genau dieser Aufbau.
<tr>-Elementen liefern, mit denselben
data-wk-depth- und aria-level-Werten, die diese Methode für die betreffende Ebene
erzeugt hätte. Passt die Tiefe nicht, bricht die Einklapp-Logik: sie leitet die Zugehörigkeit
eines Teilbaums allein aus der Tiefe ab.
Verhalten im Betrieb:
- Geladen wird höchstens einmal je Zeile. Danach entfällt der Marker und die Zeile ist ein gewöhnlicher aufgeklappter Elternknoten — Ein- und Wiederaufklappen kosten nichts mehr.
- Schlägt der Abruf fehl, entfällt der Marker ebenfalls: der nächste Klick folgt dem Link. Ein Wiederholen an gleicher Stelle würde dem Benutzer einen Knopf hinterlassen, der beliebig oft sichtbar nichts tut; Navigation funktioniert immer und zeigt den Teilbaum ebenfalls.
- Ohne JavaScript folgt der Umschalter seinem
href. Soll dieser auf eine vollständige Seite statt auf das Fragment führen, zusätzlichexpandUrlsetzen — das gewinnt dann. - Mitgelieferte Kinder schlagen
lazy: der Aufwand ist bereits bezahlt, und ein zweiter Abruf könnte dem widersprechen, was auf dem Bildschirm steht.