mitmario.dev

Listen aus Daten bauen

JavaScript Im Browser 3 Min Lesezeit 3 BeispieleLektion 7 von 9

Jetzt kommt der Vorgang zusammen, den jede Anwendung ständig macht: aus Daten wird eine Darstellung. Alles aus Abschnitt 6 und 7 trifft hier auf alles aus Abschnitt 10 und 11.

Das Muster

Das Grundmuster in vier Schritten
const kurse = [
  { id: "html", titel: "HTML", frei: true },
  { id: "css", titel: "CSS", frei: true },
  { id: "js", titel: "JavaScript", frei: false },
];

// 1. Eine Funktion, die aus EINEM Datensatz EIN Element macht.
//    Sie weiß nichts von der Seite und gibt nur zurück.
function baueEintrag(kurs) {
  const el = document.createElement("li");
  el.classList.add("eintrag");
  el.dataset.id = kurs.id;
  el.textContent = kurs.frei ? `${kurs.titel} (frei)` : kurs.titel;
  return el;
}

// 2. Eine Funktion, die die ganze Liste zeichnet.
function zeichne(liste) {
  const ziel = document.getElementById("ziel");
  ziel.replaceChildren();
  for (const kurs of liste) {
    ziel.append(baueEintrag(kurs));
  }
}

zeichne(kurse);
console.log("Einträge:", document.querySelectorAll("#ziel li").length);
console.log(document.getElementById("ziel").innerHTML);

Vier Schritte, immer dieselben:

  1. Den Container leeren. Sonst hängt beim zweiten Zeichnen alles doppelt da.
  2. Über die Daten laufen.
  3. Je Eintrag ein Element bauen.
  4. Einhängen.

Der Teil, der sich lohnt, ist die Aufteilung in zwei Funktionen. baueEintrag(kurs) macht aus einem Datensatz ein Element und gibt es zurück. Sie weiß nichts davon, wo das Element später landet, und fasst die Seite nicht an.

Das hat drei Folgen, und alle drei zahlen sich später aus. Die Funktion lässt sich einzeln prüfen, ohne dass eine Seite dasteht. Sie lässt sich woanders wiederverwenden. Und wenn die Darstellung eines Eintrags sich ändert, ist genau eine Stelle betroffen.

Das Erste kannst du wörtlich nehmen: baueEintrag({ id: "php", titel: "PHP", frei: true }) in der Eingabezeile der Console antwortet <li class="eintrag">, ein fertiges Element, das nirgends hängt. .isConnected daran antwortet false, und die Liste auf der Seite hat danach weiter drei Einträge.

zeichne(liste) kümmert sich um den Rest: leeren, laufen, einhängen.

Die Einträge stehen danach als ganz gewöhnliche Elemente auf der Seite, obwohl im Markup links nur der leere Container steht. Fahr mit dem Inspector darüber: Der Auskunftsstreifen nennt sie li.eintrag, wie jedes andere Element auch. Woher ein Element kommt, sieht man ihm nicht an, und das ist derselbe Punkt wie in Lektion 10.1.

Einmal einhängen statt fünfmal

Einmal einhängen mit einem DocumentFragment
const werte = ["A", "B", "C", "D", "E"];

function neu(text) {
  const el = document.createElement("li");
  el.textContent = text;
  return el;
}

// Fünfmal in den Baum gefasst.
const einzeln = document.getElementById("einzeln");
for (const wert of werte) {
  einzeln.append(neu(wert));
}

// Einmal in den Baum gefasst. Das Fragment ist ein Behälter,
// der beim Einhängen selbst verschwindet und nur seine
// Kinder zurücklässt.
const sammler = document.createDocumentFragment();
for (const wert of werte) {
  sammler.append(neu(wert));
}
document.getElementById("gesammelt").append(sammler);

console.log("Fragment danach:", sammler.children.length);
console.log(document.getElementById("gesammelt").children.length);

Jedes append an ein Element, das auf der Seite hängt, ist eine Änderung am Dokument. Der Browser muss darauf reagieren.

Ein DocumentFragment ist ein Behälter, der nicht auf der Seite hängt. Du sammelst darin, und beim Einhängen löst er sich auf: seine Kinder wandern in den Baum, das Fragment selbst bleibt leer zurück. Aus fünf Änderungen wird eine.

Bei fünf Einträgen ist das egal. Der Unterschied ist nicht messbar, und wer sich deshalb einen Knoten in den Code schreibt, hat nichts gewonnen. Bei dreihundert Einträgen ist er es, und dann ist es gut, das Muster schon zu kennen.

Nimm es als Gewohnheit mit: Es kostet zwei Zeilen und tut nie weh.

Der leere Zustand

Der leere Zustand als eigener Fall
function zeichne(liste, ziel) {
  ziel.replaceChildren();

  // Der leere Fall steht vorn und steigt sofort aus.
  if (liste.length === 0) {
    const hinweis = document.createElement("p");
    hinweis.classList.add("leer");
    hinweis.textContent = "Keine Kurse gefunden";
    ziel.append(hinweis);
    return;
  }

  for (const kurs of liste) {
    const el = document.createElement("article");
    el.classList.add("karte");
    el.dataset.id = kurs.id;
    el.textContent = kurs.titel;
    ziel.append(el);
  }
}

zeichne([{ id: "js", titel: "JavaScript" }], document.getElementById("mit"));
zeichne([], document.getElementById("ohne"));

console.log("mit:", document.getElementById("mit").innerHTML);
console.log("ohne:", document.getElementById("ohne").innerHTML);

Eine Liste ohne Einträge ist kein Fehler und kein Sonderfall. Sie ist ein Zustand, und sie ist häufiger, als man denkt: beim ersten Besuch, nach einer Suche ohne Treffer, nachdem der letzte Eintrag entfernt wurde.

Ohne eigene Behandlung bleibt an dieser Stelle eine leere Fläche. Für den Betrachter sieht das nach einem kaputten Programm aus, und ehrlich gesagt sieht es das zu Recht: Nichts unterscheidet „keine Treffer” von „hier hätte etwas stehen sollen”.

Deshalb steht die Abfrage vorn in der Funktion und steigt sofort aus. Ein Satz, der sagt, was los ist, und wenn es passt ein Weg heraus („Suche zurücksetzen”).

Bau ihn beim ersten Mal mit. Nachträglich eingebaut wird er meistens dann, wenn er jemandem im Betrieb aufgefallen ist.

Die Verbindung zum Datensatz

Jede Karte im dritten Beispiel trägt ein data-id. Auf der Seite sieht man davon nichts, und trotzdem ist es der wichtigste Teil.

Nach dem Zeichnen sind aus deinen Objekten Elemente geworden, und die Verbindung zwischen beiden ist erst einmal gekappt. Klickt jemand später auf eine Karte, brauchst du sie zurück: welcher Datensatz war das?

Das data-id beantwortet genau diese Frage in einer Zeile, und Abschnitt 12 baut darauf auf. Merk dir für hier: jedes erzeugte Element bekommt die Kennung seines Datensatzes mit. Das kostet nichts und erspart später eine Suche.

Zum Mitnehmen

Der leere Zustand ist kein Sonderfall, sondern ein Zustand. Bau ihn beim ersten Mal mit, nicht wenn er zum ersten Mal auffällt.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

Was in dieser Lektion steckt

  • Artikel mit 3 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe im Editor, direkt im Browser geprüft

    Öffnet sich mit dem Basis Konto.