Inhaltsverzeichnis

Nachdem du nun HTML und CSS kennst, lernst du hier die Programmiersprache JavaScript kennen. Neben einer kurzen Einführung, was man damit alles machen kann, lernst du hier wichtige Grundlagen zur Sprache selbst und wie du sie einsetzen kannst.

Lernziele dieser Einheit

Nach Abschluss dieser Einheit kannst du …

🏁

Grundlagen der Sprache JavaSscript

Bildnachweis: Pixabay: rawpixel

JavaScript im Wandel der Zeit

¹ European Computer Manufacturers Association

Bildnachweise: Pixabay: Simon, Pixabay: heladodementa, Pixabay: OpenClipart-Vectors, GNOME, Pixabay: PIX1861

Das Web als Anwendungsplattform

Bildnachweis: Wikimedia Commons

Vorhang auf für JavaScript

Klicke auf das Bild! 🖱
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Vorhang auf für JavaScript</title> <link rel="stylesheet" href="style.css" /> <script src="script.js"></script> </head> <body> <div id="theater" onclick="vorhangAufZu()"> <img src="vorhang_buehne1.jpg" class="buehne" /> <img src="vorhang_links.jpg" class="links" /> <img src="vorhang_rechts.jpg" class="rechts" /> <img src="vorhang_publikum.png" class="publikum" /> <div class="hinweis"> Klicke auf das Bild! 🖱 </div> </div> </body> </html>
#theater { padding-top: 63%; position: relative; overflow: hidden; cursor: pointer; } #theater > .buehne { position: absolute; top: 0; left: 0; width: 100%; } #theater > .links { position: absolute; top: 0; left: 0; width: 50%; transition: left 2s; } #theater > .links.offen { left: -50%; } #theater > .rechts { position: absolute; top: 0; right: 0; width: 50%; transition: right 2s; } #theater > .rechts.offen { right: -50%; } #theater > .publikum { position: absolute; bottom: 0; left: 0; width: 100%; } #theater > .hinweis { position: absolute; top: 1em; left: 1em; background: rgba(0,0,0,0.75); color: white; padding: 0.25em; }
vorhangIstOffen = false; buehnenbilder = ["vorhang_buehne1.jpg", "vorhang_buehne2.jpg", "vorhang_buehne3.jpg"]; aktuellesBild = 0; applaus1 = new Audio("vorhang_auf.ogg"); applaus2 = new Audio("vorhang_zu.ogg"); function vorhangAufZu() { let buehne = document.querySelector("#theater > .buehne"); let vorhangLinks = document.querySelector("#theater > .links"); let vorhangRechts = document.querySelector("#theater > .rechts"); if (!vorhangIstOffen) { vorhangIstOffen = true; applaus1.currentTime = 0; applaus1.play(); vorhangLinks.classList.add("offen"); vorhangRechts.classList.add("offen"); } else { vorhangIstOffen = false; applaus2.currentTime = 0; applaus2.play(); vorhangLinks.classList.remove("offen"); vorhangRechts.classList.remove("offen"); aktuellesBild++; if (aktuellesBild >= buehnenbilder.length) aktuellesBild = 0; window.setTimeout(() => buehne.src = buehnenbilder[aktuellesBild], 2100); } }

Bildnachweise: Pixabay: Geralt, Pixabay: cezary_p, Pixabay: skeeze, Pixabay: sandrocisternas, Pixabay: StockSnap
Audionachweise: Freesound: RHumphries, Freesound: misjoc

JavaScript zum Anfassen

JS.Scratch – Interaktiver JavaScript-Editor

Das ist ja gar nicht so anders

Variablen deklarieren

Variablen werden in JavaScript nicht wirklich deklariert. Sie entstehen einfach, sobald man ihnen einen Wert zuweist. Nicht vorhandene Variablen führen auch nicht zu einem Fehler, sondern liefern immer den Wert undefined.

meinName = "Arthur Dent"; let meinAlter = 31; const telefonnummer = "+49 721 12345";

Etwas ungewöhnlich ist, dass Variablen automatisch globale Variablen sind, wenn man ihnen nicht const oder let voranstellt. Hier musst du also wirklich aufpassen, damit es nicht zu diffizilen, schwer zu findenden Fehlern kommt. Älterer Code nutzt noch var, neuer Code sollte stattdessen aber immer let verwenden, da es die Gültigkeit der Variablen noch mehr eingrenzt. Mit const kannst du im Gegensatz zu let Konstanten definieren. Eine Variable, deren Wert nicht neu zugewiesen wird, sollte als Konstante definiert werden. Kann der Wert überschriben werden, verwende let.

let fisch = "Wanda The Fish"; fisch = 27;

Da JavaScript keine wirkliche Deklaration von Variablen kennt, wird auch ihr Typ nicht fest vorgegeben. Stattdessen hängt es immer davon ab, was man gerade in eine Variable reinschreibt. Im obigen Beispiel handelt es sich bei der Variable erst um einen String und dann um eine Zahl. Das ist zwar nicht schön, aber durchaus erlaubt.

String meinName = "Arthur Dent"; int meinAlter = 31; String telefonnummer = "+49 721 12345";

Java kennt keine globalen Variablen. Jede Variable gilt nur innerhalb der Klasse oder Methode, in der sie definiert wurde. Dafür müssen Variablen immer erst deklariert werden, bevor sie verwendet werden können. Üblicherweise wird den Variablen bei der Deklaration allerdings gleich ein Wert zugewiesen. Der obige Quellcode hätte daher auch so geschrieben werden können:

String meinName, telefonnummer; int meinAlter; meinName = "Arthur Dent"; meinAlter = 31; telefonnummer = "+49 721 12345";

Im Gegensatz zu JavaScript wird der Typ einer Variable durch ihre Deklaration bestimmt. In JavaScript hingegen ergibt sich der Typ aus dem Inhalt der Variable und kann sich jederzeit ändern. Für das zweite JavaScript-Beispiel gibt es daher keine wirkliche Entsprechung in Java. Nur eine weit hergeholte Version mit den so genannten Boxed Types:

Object fisch = new String("Wanda The Fish"); fisch = new Integer(31);

Funktionen und Methoden aufrufen

Funktionen und Methoden werden in JavaScript genauso aufgerufen wie in Java. Nur mit dem einen Unterschied, dass Java keine Funktionen (Methoden ohne Klassen) kennt.

let startButton = document.getElementById("start"); showGameOverScreen("Game Over", "Nochmal versuchen", true);
DOMNode startButton = document.getElementById("start"); this.showGameOverScreen("Game Over", "Nochmal versuchen", true);

Das sieht fast gleich wie bei JavaScript aus. Nur, dass der Variable startButton ein expliziter Typ mitgegeben werden muss und dass Java keine Methoden ohne Klassen kennt. Zwar wäre die folgende Zeile durchaus zulässig:

showGameOverScreen("Game Over", "Nochmal versuchen", true);

Sie ist aber nichts anderes als folgende Zeile:

this.showGameOverScreen("Game Over", "Nochmal versuchen", true);

Fallunterscheidungen

if (alter < 18) { … } else if (alter < 60) { … } else { … }

Hier gibt es fast gar keine Unterschiede zu Java. Lediglich den Operator === kennt Java nicht: Er prüft nicht nur, ob zwei Variablen inhaltlich gleich sind, sondern auch ob sie denselben Typ haben:

if (42 == "42") { // Trifft tatsächlich zu } if (42 === "42") { // Trifft nicht zu }

An diesem Beispiel siehst du auch, dass JavaScript Strings direkt vergleichen kann. Eine equals()-Methode brauchen wir hierfür nicht:

let person1 = "Willy"; let person2 = "Alf"; if (person1 === person2) { … } else if (person1 != person2) { … }

Das switch-Statement hingegen sieht genau wie in Java aus:

switch (event.type) { case "keydown": … break; case "click": … break; default; … }
if (alter < 18) { … } else if (alter < 60) { … } else { … }

if-Abfragen sehen genau wie in JavaScript aus, nur dass es den ===-Operator nicht gibt und dass zwei Strings über ihre equals()- bzw. equalsIgnoreCase()-Methoden verglichen werden müssen.

if (42 == "42") { // Kann nie zutruffen } String person1 = "Willy"; String person2 = "Alf"; if (person1.equals(person2)) { … } else if (!person1.equals(person2)) { … }

switch/case sieht genau gleich aus:

switch (event.type) { case "keydown": … break; case "click": … break; default; … }

Schleifen

while (i > 0) { … i--; } do { … i--; } while (i > 0); for (let i = 0; i < 100; i++) { … }

while,- do- und for-Schleifen sehen alle wie in Java aus. For-Each-Schleifen funktionieren jedoch anders:

let kontakte = ["Bernd", "Michael", "Stéphane", "Luis"]; for (let i in kontakte) { let kontakt = kontakte[i]; … }

Noch moderner geht es mit einer Lambda-Funktion, was Java inzwischen auch kann:

kontakte.forEach(kontakt => { … });
while (i > 0) { … i--; } do { … i--; } while (i > 0); for (int i = 0; i < 100; i++) { … }

Bis hierhin alles beim Alten. Lediglich innerhalb der for-Schleife wurde das let durch int ersetzt. For-Each-Schleifen sehen in Java hingegen so aus:

String kontakte[] = {"Bernd", "Michael", "Stéphane", "Luis"}; for (String kontakt : kontakte) { … }

Das andere Konstrukt mit der forEach()-Methode gibt es seit Java 8 auch:

import java.util.Arrays; Arrays.stream(kontakte).forEach((kontakt) -> { … });

Noch schöner ist es allerdings, wenn die Daten von Anfang an als Collection vorliegen. Dann spart man sich die Umwandlung des Arrays in einen Stream:

import java.util.ArrayList; import java.util.List; List<String> kontakte = new ArrayList<>(); kontakte.put("Bernd"); kontakte.put("Michael"); kontakte.put("Stéphane"); kontakte.put("Luis"); kontakte.forEach((kontakt) -> { … });

Mehr über Variablen und Funktionen

Datentypen in JavaScript

🎓 Merke: JavaScript ist eine schwach typisierte, dynamische Sprache.
🎓 Und merke: Globale Variablen hängen am window-Objekt.

Definition einfacher Funktionen

Alte Syntax mit dem Schlüsselwort function:

function halloWelt(name, alter) { return `Hallo ${name}. Du bist ${alter} Jahre alt.`; }

Für neuen Code empfohlene Schreibweise:

let halloWelt = (name, alter) => { return `Hallo ${name}. Du bist ${alter} Jahre alt.`; };

Oder noch kürzer:

let halloWelt = (name, alter) => return `Hallo ${name}. Du bist ${alter} Jahre alt.`;

Oder am kürzesten:

let halloWelt = (name, alter) => `Hallo ${name}. Du bist ${alter} Jahre alt.`;

Aufgabe 1: Berechnung der Fakultät

Aus dem Mathematikunterricht kennst du sicher noch die Fakultätfunktion. Sie ist so definiert, dass sie einer natürlichen Zahl 𝑛 > 0 das Produkt aller natürlichen Zahlen von 𝑛 … 1 zuordnet. Am einfachsten lässt sich das an einem Beispiel zeigen:

5! = 5 × 4 × 3 × 2 × 1 = 120
10! = 10 × 9 × 8 × 7 × 6 × 5 × 4 × 3 × 2 × 1 = 3.628.800

Alles klar? Deine Aufgabe lautet, eine JavaScript-Funktion zu schreiben, mit der die Fakultät einer beliebigen Zahl berechnet werden kann. Du kannst die Funktion dabei entweder rekursiv durch Aufruf von sich selbst oder iterativ mit einer Schleife programmieren. In jedem Fall solltest du aber prüfen, ob die übergebene Zahl größer 0 ist und den Wert NaN¹ zurück liefern, falls nicht.

Zum Ausprobieren, kannst du die Funktion direkt in JS.Scratch aufrufen. um Beispiel so:

let faktultaet = n => { return … };
fakultaet(5);
number 120

¹ NaN steht für „Not A Number”.

let fakultaet = n => { if (n < 1) { return NaN; } else if (n == 1) { return 1; } else { return n * fakultaet(n-1); } };

Vorsicht: Diese Lösung nutzt Rekursion und kann daher nur für relativ kleine Zahlen verwendet werden. Ist die Zahl 𝑛 zu groß, kommt es möglicherweiße zu einem Abbruch.

let fakultaet = n => { if (n < 1) { return NaN; } let ergebnis = 1; for (let i = 1; i <= n; i++) { ergebnis *= i; } return ergebnis; };

Diese Lösung nutzt anstelle der Rekursion eine Schleife und funktioniert daher mit allen Zahlen.

Hinweis: ergebnis *= i ist dasselbe wie ergebnis = ergebnis * i. Analog dazu gibt es noch +=, -= und /=.

Aufgabe 2: Lokale und globale Variablen

Schaue dir den folgenden JavaScript-Code und lasse ihn auch mal in JS.Scratch laufen. Anschließend beantworte die folgenden Fragen:

let fibonacci = n => { if (n < 1) return NaN; ergebnis = 0; for (let i = n; i >= 1; i--) { ergebnis += i; } return ergebnis; }; ergebnis = fibonacci(10); ergebnis1 = fibonacci(20);

a) Welchen Wert hat die Variable ergebnis nach Aufruf der Funktion fibonacci(10)?

b) Welchen Wert hat die Variable ergebnis nach Aufruf der Funktion fibonacci(20)?

c) Wie lässt sich dieser Fehler korrigieren?

d) Wie lässt sich innerhalb einer Funktion kenntlich machen, dass eine globale Variable angesprochen werden soll?

a) Wie erwartet bekommt die Variable den Wert 55 zugewiesen.

b) Die Variablen ergebnis und ergebnis1 haben beide den Wert 210. Das war so nicht gewollt, da das Ergebnis nur in ergebnis1 gespeichert werden sollte.

c) In der Funktion muss ergebnis = 0 durch let ergebnis = 0 oder const ergebnis = 0 ersetzt werden:

let fibonacci = n => { if (n < 1) return NaN; let ergebnis = 0; for (let i = n; i >= 1; i--) { ergebnis += i; } return ergebnis; };

d) Durch Zugriff auf das window-Objekt, zum Beispiel so: window.ergebnis = 55;

Aufgabe 3: Ein kleines JavaScript-Quiz

Was bewirken die folgenden Quellcode-Schnippsel?

a) let ergebnis = 42;

  1. Deklaration einer globalen Variable mit dem Wert 42 (überall sichtbar)
  2. Deklaration einer lokalen Variable mit dem Wert 42 (nur in der aktuellen Funktion sichtbar)
  3. Prüfung, ob die Variable ergebnis den Wert 42 enthält

b) ergebnis = 42;

  1. Deklaration einer globalen Variable mit dem Wert 42 (überall sichtbar)
  2. Deklaration einer lokalen Variable mit dem Wert 42 (nur in der aktuellen Funktion sichtbar)
  3. Prüfung, ob die Variable ergebnis den Wert 42 enthält

c) multiply = (a, b) => a * b;

  1. Deklaration der beiden Variablen a und b und anschließende Multiplikation der beiden Werte
  2. Definition einer Liste mit den Werten a und b mit anschließender Multiplikation der beiden Werte
  3. Definition einer Funktion, die zwei Zahlen miteinander multipliziert

d) ergebnis = 42; ergebnis = "zweiundvierzig";

  1. Die Variable ergebnis ist erst ein Integer, dann ein String
  2. Umwandlung des Werts in der Variablen ergebnis von einem String in einen Integer
  3. Syntaxfehler: Das ist in JavaScript so nicht erlaubt

Lösung: 2, 1, 3, 1

Funktionen – Nichts Besonderes

Anatomie einer Funktionsdefinition

Rückruffunktionen für Events

Häufig erwartet eine Funktion eine andere Funktion als Parameter, um diese bei Eintreten eines Ereignisses aufrufen zu können. Die aufgerufene Funktion nennt man Rürckruffunktion oder auch Callback:

let callback = () => { … }; let div = document.getElementById("theater"); div.addEventListener("click", callback);

Lässt sich verkürzen zu:

let div = document.getElementById("theater"); div.addEventListener("click", () => { … });

Funktionen höherer Ordnung

Funktionen höherer Ordnung sind Funktionen, die als Rückgabewert eine neue Funktion liefern:

let erzeugeFunktion = name => { return () => `Hello, ${name}!`; } let begruesseKitty = erzeugeFunktion("Kitty"); console.log(begruesseKitty());

Gibt auf der Konsole Hello, Kitty! aus.

Von Arrays und Wörterbüchern

Arrays (bzw. Listen)

Arrays in JavaScript beinhalten einfach eine beliebige Anzahl von Einträgen. Üblicherweise haben alle Einträge denselben Datentyp, dies ist aber kein Muss. Um einen Eintrag anzusprechen, muss man seinen Index kennen, der genau wie in Java bei 0 beginnt.

let einkaufsliste = ["Brot", "Milch", "Kaffee", "Nutella",]; let lottozahlen = [3, 12, 24, 28, 31,];

Im folgenden Beispiel sieht man, dass ein Array wie wild alle möglichen Datentypen mischen kann. Das Array beinhaltet zum Beispiel die Namen zweier Spieler sowie drei weitere Arrays, die zusammen ein Tic-Tac-Toe-Spielfeld simulieren, und ein Boolean.

let ticTacToe = [ "Spieler 1", "Spieler 2", [2,0,1], [2,1,0], [1,0,0], false, ];

Um einen Eintrag aus einem Array zu holen, benötigt man seinen Index. Zum Beispiel einkaufsliste[1]. Mit einer einfachen for-Schleife oder der forEach-Methode kann man alle Einträge eines Arrays abarbeiten.

for (let i = 0; i < einkaufsliste.length; i++) { console.log(einkaufsliste[i]); } lottozahlen.forEach(zahl => { console.log(zahl); })

Arrays in Java beinhalten ebenfalls eine beliebige Anzahl von Einträgen, die über ihren Index angesprochen werden. Jedoch müssen alle Inhalte denselben Datentyp besitzen. Man kann zum Beispiel nicht ohne weiteres Strings und Integer in einem Array mischen. Außerdem ist auch die Syntax viel komplizierter.

String[] einkaufsliste = {"Brot", "Milch", "Kaffee", "Nutella",}; int[] lotozahlen = {3, 12, 24, 28, 31}; int[][] ticTacToeSpielfeld = { new int[] {2, 0, 1}, new int[] {2, 1, 0}, new int[] {1, 0, 0}, }

Der Zugriff erfolgt entweder per Index oder über eine For-Each-Schleife:

for (int i = 0; i < einkaufsliste.length; i++) { System.println(einkfaufsliste[i]); } for (String eintrag : einkaufsliste) { System.println(eintrag); }

Seit Java 8 kann man auch eine Lambda-Funktion nutzen:

import java.util.Arrays; Arrays.stream(einkaufsliste).forEach((eintrag) -> { System.println(eintrag); })

Die direkte Verwendung von Arrays ist in Java allerdings schon lange eher unerwünscht. Stattdessen sollte man eine der verschiedenen Collection-Klassen verwenden, zum Beispiel eine Linked List:

import java.util.LinkedList; import java.util.List; List<String> einkaufsliste = new LinkedList<>(); einkaufsliste.add("Brot"); einkaufsliste.add("Milch"); einkaufsliste.add("Kaffee"); einkaufsliste.add("Nutella"); for (String eintrag : einkaufsliste) { System.out.println(eintrag); } einkaufsliste.forEach((eintrag) -> { System.out.println(eintrag); });

Dictionaries (bzw. Objekte)

Objekte in JavaScript werden auch Dictionaries genannt. Sie dienen einfach der Gruppierung mehrerer Werte zu einem Datensatz. Die Einträge eins Dictionaries werden daher über einen frei wählbaren Namen angesprochen und haben auch keine feste Reihenfolge.

const mulder = { vorname: "Fox", nachname: "Mulder", beruf: "Special Agent FBI", vorgesetzter: "Walter Skinner", partner: "Dana Scully", };

Die Syntax, um einen einzelnen Wert auszulesen ist dieselbe wie bei einer Liste, nur mit einem Namen anstelle des Index:

let vorname = mulder["vorname"]; mulder["vorgesetzter"] = "Assistant Director Walter Skinner";

Da Dictionaries und Objekte exakt dasselbe sind, kann man anstelle der eckigen Klammern auch einfach einen Punkt verwenden:

let vollerName = `${mulder.vorname} ${mulder.nachname}` mulder.partner = "Dana Katherine Scully";

Auch über die Einträge eines Dictionaries kann man iterieren. Der in-Operator liefert hierfür die Namen aller Einträge zurück:

for (let key in mulder) { console.log(mulder[key]); }

Objekte lassen sich in Java nicht direkt definieren. Man muss immer erst eine Klasse schreiben und diese dann instantiieren:

public class Person { public String vorname = ""; public String nachname = ""; public String beruf = ""; public String vorgesetzter = ""; public String partner = ""; } Person mulder = new Person(); mulder.vorname = "Fox"; mulder.nachname = "Mulder"; mulder.beruf = "Special Agent FBI"; mulder.vorgesetzter = "Walter Skinner"; mulder.partner = "Dana Scully";

Allerdings gibt es mit der Map etwas ähnliches wie Dictionaries. Denn eine Map bildet einen beliebigen Schlüsselwert auf ein beliebiges Objekt ab. Dictionaries entsprechen daher am ehestem folgendem Konstrukt in Java:

import java.Util.HashMap; import java.util.Map; Map<String, Object> mulder = new HashMap<>(); mulder.put("vorname", "Fox"); mulder.put("nachname", "Mulder"); mulder.put("beruf", "Special Agent FBI"); …

Komplexe Strukturen mit Arrays und Dictionaries

Indem man Arrays und Dictionaries kombiniert, kann man beliebig komplexe Datenstrukturen zusammensetzen. Das Format ist dabei so beliebt, dass es auch unter dem Namen JSON¹ als eigenständiges Datenformat existiert und unter anderem zum Datenaustausch mit dem Server genutzt werden kann. Hier ein Beispiel mit einem alten Disney-Klassiker: 🦁

let dieTollkuehneHexe = { titel: "Die Tollkühne Hexe in ihrem fliegenden Bett", originalTitel: "Bedknobs and Broomsticks", land: "USA", originalSprache: "englisch", jahr: 1971, darsteller: [ "Angela Lansbury", "David Tomlinson", "Roddy McDowall", "Sam Jaffe", "John Ericson", "Bruce Forsyth", "Cindy O’Callaghan", "Roy Snart", "Ian Weighill", "Tessie O’Shea", "Arthur Gould-Porter", "Reginald Owen", "Ben Wrigley", "Cyril Delevantiv", ], };

Will man nun den Namen von Angela Lansbury auslesen, kann man mit folgenden Ausdrücken darauf zugreifen:

  • dieTollkuehneHexe["darsteller"][0]
  • dieTollkuehneHexe.darsteller[0]

Natürlich kann man auch ein Array mit Dictionaries drin definieren:

let filme = [ { titel: "Die tollkühne Hexe in ihrem fliegenden Bett", land: "USA", jahr: 1971, darsteller: [ "Angela Lansbury", "David Tomlinson", "Roddy McDowall", … ] }, { titel: "Spaceballs", land: "USA", jahr: 1987, darsteller: [ "Mel Brooks", "John Candy", "Rick Moranis", … ] }, { titel: "M - Eine Stadt sucht einen Mörder", land: "Deutschland", jahr: 1931, darsteller: [ "Peter Lorre", "Inge Landgut", "Ellen Widmann", … ] } ];

Du siehst, das ganze ist wahnsinnig flexibel und auch noch einfach zu schreiben. 👍

¹ JavaScript Object Notation

Vergiss es. Ohne Klassen läuft in Java nichts. 😛 Diese müssen wir erst einmal definieren. Zum Glück speichern wir bei den Darstellern nur die Namen. Denn sonst hätten wir dafür auch nochmal eine Klasse gebraucht. Will man es besonders schön machen, muss man sogar für jedes Attribut eine Setter- und eine Getter-Methode anlegen.

import java.util.ArrayList; import java.util.List; public class Film { private String titel = ""; private String originalTitel = ""; private String land = ""; private String originalSprache = ""; private int jahr = 0 private List<String> darsteller = new ArrayList<>(); public void setTitel(String titel) { this.titel = titel; } public String getTitel() { return this.titel; } … gefühlte 1000 Zeilen später … }

Dann können wir endlich ein Objekt erzeugen:

Film dieTollkuehneHexe = new Film(); dieTollkuehneHexe.setTitel("Die tollkühne Hexe in ihrem fliegenden Bett"); dieTollkuehneHexe.setOriginalTitel("Beknobs and Broomsticks"); dieTollkuehneHexe.setLand("USA"); dieTollkuehneHexe.setOriginalSprache("Englisch"); dieTollkuehneHexe.setJahr(1971); dieTollkuehneHexe.darsteller.add("Angela Lansbury"); dieTollkuehneHexe.darsteller.add("David Tomlinson"); dieTollkuehneHexe.darsteller.add("Roddy McDowall"); dieTollkuehneHexe.darsteller.add("Sam Jaffe"); …

Natürlich hätten wir noch ein paar Sachen vereinfachen können. Zum Beispiel indem wir der Klasse einen gescheiten Konstruktor und ein paar Hilfsmethoden spendiert hätten. Weniger Quellcode wäre es deshalb natürlich nicht geworden. Die Klasse Film wäre aber angenehmer zu verwenden gewesen (worauf man immer achten sollte 😌).

Aufgabe 4: Verstehst du das?

Welches Ergebnis liefert der folgende Quellcode?

caesar = [ () => "Veni, Vidi, Vici", // Ich kam, sah und siegte () => "Alea iacta est", // Die Würfel sind gefallen () => "Cras legam", // Morgen werde ich es lesen ]; zusammenfuegen = (string, callback) => { return string + ": " + callback(); } ergebnis = zusammenfuegen("Cäsar", caesar[1]);

Lösung: „Cäsar: Alea iacta est” 🎲🎲

Aufgabe 5: Ein kleines JSON-Quiz

Was bewirken die folgenden Quellcode-Schnippsel?

a) let movie = {id: 1, name: "Moon", year: 2009};

  1. Definition einer Liste mit drei Werten
  2. Definition eines Dictionaries mit drei Werten
  3. Definition dreier Variablen

b) let favorites = ["Toy Story", "Anchorman", "Gravity", "The Founder"];

  1. Definition eines Dictionaries mit vier Werten
  2. Definition einer Liste mit vier Werten
  3. Definition einer Methode mit vier Parametern

c) let cds = [{name: "Tracker", year: 2015}, {name: "Privateering", year: 2013}];

  1. Definition einer Liste mit zwei Dictionaries
  2. Definition eines Dictionaries mit zwei Listen
  3. Definition von vier Variablen

Lösung: 2, 2, 1

Aufgabe 6: Talk JSON to me

Angenommen du hast eine Datenbank mit folgenden Tabellen. Wie können dieselben Daten in JavaScript beschrieben werden?

Alben

ID Albumtitel Künstler Jahr
1 Tracker Mark Knopfler 2015
2 X Ed Sheran 2014
3 Liquid Spirit Gregory Porter 2013

Titel

Album ID Track Songtitel
1 1 Laughs And Jokes And Drinks And Smokes
1 2 Basil
2 1 One
2 2 I'm A Mess
3 1 No Love Dying

a) Schreibe eine JavaScript/JSON-Datei, die exakt dieselben Daten enthält. Anstelle von zwei Listen solltest du jedoch nur eine Liste haben, in der sowohl die Alben als auch ihre Titel enthalten sind.

b) Wie kann anschließend auf den Songtitel „Basil” zugegriffen werden?

a) Anmerkung: Das ist nur eine mögliche Lösung. Statt des Arrays auf oberster Ebene wäre auch ein Dictionary denkbar, bei dem die Album-ID als Schlüsselwert benutzt wird. Die Songtitel sollten sinnvollerweise auf jeden Fall in einem Array gespeichert werden. Das Array könnte aber anstatt der Strings auch Dictionaries enthalten, so dass zu jedem Songtitel noch weitere Daten gespeichert werden könnten.

let alben = [ { id: 1, albumtitel: "Tracker", kuenstler: "Mark Knopfler", jahr: 2015, songtitel: ["Laughs And Jokes And Drinks And Smokes", "Basil", …], }, { id: 2, albumtitel: "X", kuenstler: "Ed Shearn", jahr: 2014, songtitel: ["One", "I'm A Mess", … ], }, { id: 3, albumtitel: "Liquid Spirit", kuenstler: "Gergory Porter", jahr: 2013, songtitel: ["No Love Dying", … ], }, ];

b) Auf den Titel „Basil” kann mit alben[0]["songtitel"][1] zugegriffen werden.

DOM-Manipulation mit JavaScript

Bildnachweis: Pixabay: rawpixel

JavaScript in HTML einbinden

Direkt im HTML-Code

<!DOCTYPE html> <html> <head> <title>JavaScript und HTML in einer Datei</title> <meta charset="utf-8" /> <style> html, body { font-size: 16pt; font-family: sans-serif; } … </style> <script> window.addEventListener("load", () => { let klickMichButton = document.getElementById("klick-mich-button"); let ergebnisDiv = document.getElementById("ergebnis"); let anzahl = 0; klickMichButton.addEventListener("click", () => { anzahl++; ergebnis.textContent = `Du hast mich ${anzahl} mal angeklickt.`; if (anzahl > 2) { ergebnis.innerHTML += "<br /> Du hast einen einfachen Button sehr glücklich gemacht." } }); }); </script> </head> <body> <button id="klick-mich-button">Klick mich</button> <div id="ergebnis"></div> </body> </html>

In einer separaten Datei

<!DOCTYPE html> <html> <head> <title>JavaScript und HTML in einer Datei</title> <meta charset="utf-8" /> <!-- Stylesheet und JavaScript nun in eigenen Dateien --> <link rel="stylesheet" href="style.css" /> <script src="button-script.js"></script> </head> <body> <button id="klick-mich-button">Klick mich</button> <div id="ergebnis"></div> </body> </html>
html, body { font-size: 16pt; font-family: sans-serif; } button { font-size: 150%; background-color: #353F8E; color: white; border: none; } button:hover, button:active, button:focus, button::-moz-focus-inner { outline: 0; border: 0; } #ergebnis { font-weight: bold; color: crimson; margin-top: 1em; }
window.addEventListener("load", () => { let klickMichButton = document.getElementById("klick-mich-button"); let ergebnisDiv = document.getElementById("ergebnis"); let anzahl = 0; klickMichButton.addEventListener("click", () => { anzahl++; ergebnisDiv.textContent = `Du hast mich ${anzahl} mal angeklickt.`; if (anzahl > 2) { ergebnisDiv.innerHTML += "<br /> Du hast einen einfachen Button sehr glücklich gemacht."; } }); });

Entwicklerwerkzeuge, Teil 2

Die Browserkonsole

Der Debugger

Bildnachweis für das Endesymbol: Pixabay: janf93

Aufgabe 7: Finde den Fehler

Lade dir den Quellcode zu dieser Aufgabe herunter und schaue dir die HTML-Datei aus dem Verzeichnis Aufgabe im Browser an. Es handelt sich um ein einfaches Memoryspiel.

Doch leider läuft das Spiel noch nicht richtig. Wenn man eine Karte anklickt, passiert noch nichts, obwohl in der Datei script.js in Zeile 67 ein entsprechender Event Listener registriert wird. Um diesen Fehler zu finden, solltest du die Funktionen onCardClicked und startGame debuggen. Der Fehler ist dann ziemlich offensichtlich. 😰

Wenn das Umdrehen der Karten klappt, wirst du feststellen, dass das Spiel immer noch nicht läuft. Eigentlich sollte beim Aufklappen der zweiten Karte geprüft werden, ob die beiden Karten übereinstimmen und nur, wenn das der Fall ist, sollten die Karten offen liegen bleiben. Stattdessen bleiben die Karten aber einfach immer offen, auch wenn sie nicht identisch sind. Auch hier wirst du wohl debuggen müssen. Aber keine Angst, die Korrektur ist ziemlich einfach. 🙈

Das sieht noch nicht ganz richtig aus …

Oh je! Wenn du hier schauen musst, hast du die beiden Fehler nicht gefunden. 😔 Na gut, dann wollen wir dir mal weiter helfen:

  1. In Zeile 51 fehlt ein s. Es muss "#cards > img" statt "#card > img" heißen.
  2. Die Aufrufe in den Zeilen 103 und 104 sind vertauscht. Es muss erst die Funktion flipCard(card) aufgerufen werden, um die angeklickte Karte umzudrehen. Erst dann können die Karten mit compareCards(card) verglichen werden.

Zugriff auf vorhandene HTML-Elemente

Auf HTML-Elemente wird über das Document Object Model zugegriffen.
Das document-Objekt dient hierfür als zentraler Einstiegspunkt.

Einzelne HTML-Elemente auslesen

let mainContentElement = document.getElementById("main-content");

Gibt ein einzelnes HTML-Element mit der gesuchten ID (Attribut id) zurück. Gibt es kein solches Element, ist die Antwort stattdessen null.

let firstImage = document.querySelector("main > img:first-child");

Führt den übergebenen CSS-Selektor aus und gibt das erste HTML-Element zurück, auf das die Suche zutrifft. Wurde kein passendes Element gefunden, ist die Antwort ebenfalls null.

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Einzelne DOM-Elemente auslesen</title> </head> <body> <h1>Einzelne DOM-Elemente auslesen</h1> <p id="hinweis"> Klicke einen der beiden Knöpfe. </p> <button onclick="getElementByIdClicked()">Element mit ID „hinweis”</button> <button onclick="querySelectorClicked1()">Das erste &lt;h1&gt;</button> <button onclick="querySelectorClicked2()">Das erste &lt;h2&gt;</button> <script> getElementByIdClicked = () => { let hinweis = document.getElementById("hinweis"); alert(hinweis.outerHTML); } querySelectorClicked1 = () => { let heading = document.querySelector("h1") alert(heading.outerHTML); } querySelectorClicked2 = () => { let heading = document.querySelector("h2") // heading ist null !! alert(heading); } </script> </body> </html>

Einzelne DOM-Elemente auslesen

Klicke einen der beiden Knöpfe.

Mehrere HTML-Elemente auslesen

let containerElements = document.getElementsByClassName("container");

Liefert eine Liste aller HTML-Elemente, denen die Klasse container zugewiesen wurde.

let allThumbnails = document.querySelectorAll("img.thumbnail");

Liefert alle <img>-Elemente, die gleichzeitig noch die Klasse thumbnail besitzen. Die Syntax für den Abfrageparameter ist dieselbe wie für CSS-Selektoren.

let firstThumbnail = allThumbnails[0];
allThumbnails.forEach(element => …);

Auch wenn man es zunächst denken würde, aber das Ergebnis der Methoden getElementsByClassName und querySelectorAll ist kein Array. getElementsByClassName liefert eine HTMLCollection und querySelectorAll ein NodeList-Objekt. Beide verhalten sich ähnlich wie Arrays, besitzen aber nicht ganz dieselben Methoden. Die forEach-Methode zum Beispiel funktioniert nur beim Ergebnis von querySelectorAll. 😕

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Einzelne DOM-Elemente auslesen</title> </head> <body> <h1>Mehrere DOM-Elemente auslesen</h1> <ol> <li class="erledigt"> Einführung in die Vorlesung </li> <li class="erledigt"> Grundlagen des Web </li> <li class="erledigt"> Einstieg in HTML </li> <li class="in-arbeit"> Layouts erstellen mit CSS </li> <li class="in-arbeit"> Responsive Webdesign </li> </ol> <button onclick="getElementsByClassNameClicked()">Alle mit Klasse „erledigt”</button> <button onclick="querySelectorAllClicked1()">Alle li.in-arbeit</button> <button onclick="querySelectorAllClicked2()">Alle li.nicht-in-arbeit</button> <script> getElementsByClassNameClicked = () => { let result = document.getElementsByClassName("erledigt"); showResult(result); } querySelectorAllClicked1 = () => { let result = document.querySelectorAll("li.in-arbeit"); showResult(result); } querySelectorAllClicked2 = () => { let result = document.querySelectorAll("li.nicht-in-arbeit"); showResult(result); } showResult = domNodes => { console.log(domNodes); let text = `Anzahl gefunden: ${domNodes.length}\n\n`; for (let i = 0; i < domNodes.length; i++) { text += domNodes.item(i).outerHTML + "\n\n"; } alert(text) } </script> </body> </html>

Mehrere DOM-Elemente auslesen

  1. Einführung in die Vorlesung
  2. Grundlagen des Web
  3. Einstieg in HTML
  4. Layouts erstellen mit CSS
  5. Responsive Webdesign

Ereignisse abfangen und behandeln

saveButton.addEventListener("click", …);

Jedes HTML-Element kann eine Reihe von Ereignissen auslösen, auf die man mit JavaScript reagieren kann. Hierfür besitzt jedes Element die Methode addEventListener. Der erste Parameter ist der Name des Ereignisses, der zweite Parameter eine Funktion, die bei Eintreten des Ereignisses aufgerufen wird.

🎓 Merke: Funktionen sind vollwertige Objekte und können daher direkt als Parameter übergeben werden.

🎓 Achtung: Da JavaScript den gesamten Code in einem einzigen Thread ausführt, dürfen die Event-Handler-Funktionen nicht lange laufen. Sonst wird die gesamte Seite ruckelig, weil im selben Thread auch die Bildschirmausgabe erzeugt wird. ⏳

Ereignis Bedeutung
click Einfacher Linksklick mit der Maus oder dem Touchscreen
mouseover Der Mauszeiger befindet sich innerhalb des Elements.
mouseout Der Mauszeiger befindet sich nicht mehr über dem Element.
keydown Beginn eines Tastendrucks auf der Tastatur. Die Taste wurde herunter gedrückt.
keyup Ende eines Tastendrucks auf der Tastatur. Die Taste wurde wieder losgelassen.

Eine gute Übersicht gibt es im Mozilla Developer Network. Da der Browser aber keine komplexen Gesten erkenn kann (Swipe Left, Double Tap, …) muss man hierfür externe Bibliotheken wie Hammer.JS verwenden.

saveButton.addEventListener("click", event => …);

Jeder Event Listener bekommt als ersten Parameter ein Event-Objekt übergeben. In event.target findet sich dann zum Beispiel das HTML-Element, das das Ereignis ausgelöst hat. Es gibt aber noch weitere, interessante Methoden, die gelegentlich nützlich sein können.

window.addEventListener("load", …)

Ein besonders häufig genutztes Ereignis ist das load-Ereignis des window-Objekts. Es zeigt an, dass die HTML-Seite komplett geladen wurde und nun auf das Document Object Model zugegriffen werden kann. Denn der Quellcode aller <script>-Elemente wird sofort ausgeführt, sobald der Browser sie findet. In der Regel ist die Seite zu diesem Zeitpunkt aber noch gar nicht komplett geladen und Zugriffe auf das Document Object Model schlagen fehl.¹

Will man daher beim Laden der Seite zuverlässig auf das Document Object Model zugreifen, muss man erst das load-Ereignis abwarten und in dessen Event Handler alle weiteren Schritte ausführen.

¹ Man nennt das eine „Race Condition”, da der JavaScript-Code mit dem Browser um die Wette läuft. 🏃🏃

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Auf Ereignisse reagieren</title> <style> #preview { display: block; width: 25em; padding: 0.25em; background: #F0F0F0; border: 1px solid #A0A0A0; margin-bottom: 1em; } </style> </head> <body> <h1>Auf Ereignisse reagieren</h1> <img id="preview" /> <button id="next-button">Weiter</button> <button id="prev-button">Zurück</button> <script> window.addEventListener("load", () => { let previewElement = document.getElementById("preview"); let nextButton = document.getElementById("next-button"); let prevButton = document.getElementById("prev-button"); let images = [ "img/preview1.jpg", "img/preview2.jpg", "img/preview3.jpg" ]; let index = -1; switchImage = direction => { index += direction; if (index >= images.length) index = 0; if (index < 0) index = images.length - 1; previewElement.src = images[index]; } switchImage(1); nextButton.addEventListener("click", () => switchImage(1)); prevButton.addEventListener("click", () => switchImage(-1)); }); </script> </body> </html>

Auf Ereignisse reagieren

Beispiel: Stoppuhr

Gestoppt
0
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Event Handler und Closures in JavaScript</title> <link rel="stylesheet" href="style.css" /> <script src="script.js"></script> </head> <body> <div id="toolbar"> <button id="button-plus-one">➕ Zähler erhöhen</button> <button id="button-minus-one">➖ Zähler vermindern</button> <button id="button-start-stop">▶ Start/Stop</button> <div id="status" class="right"></div> </div> <div id="counter"></div> </body> </html>
html, body { padding: 0; margin: 0; min-height: 100%; font-family: sans-serif; font-size: 14pt; } body { background: linear-gradient(to bottom, rgba(254,255,255,1) 0%,rgba(210,235,249,1) 100%); } #toolbar { background-color: #2566A4; color: white; margin: 0; padding: 0; padding-left: 1rem; padding-right: 1rem; } #toolbar button, #toolbar div { background: none; border: none; outline: 0; color: white; font-size: 95%; padding: 0.75em 0.25em 0.75em 0.25em; } #toolbar button:hover { background: rgba(255, 255, 255, 0.25); cursor: pointer; } #toolbar button:active { padding: 0.8em 0.15em 0.7em 0.35em; } #toolbar button:hover, #toolbar button:active, #toolbar button:focus, #toolbar button::-moz-focus-inner { outline: 0; border: 0; } #toolbar .right { float: right; } #counter { text-align: center; font-size: 80vmin; color: darkred; text-shadow: 1px 1px 2px rgba(0,0,0,0.75); }
// Der Event Handler für das load-Event wird erst ausgeführt, wenn die // Seite geladen und der DOM-Baum komplett verfügbar ist. window.addEventListener("load", () => { // Lokale Variablen mit den HTML-Elementen der Seite let buttonPlusOne = document.getElementById("button-plus-one"); let buttonMinusOne = document.getElementById("button-minus-one"); let buttonStartStop = document.getElementById("button-start-stop"); let statusElement = document.getElementById("status"); let counterElement = document.getElementById("counter"); // Aktueller Zählerstand let counter = 0; let running = false; let lastUpdate = 0; // Event Handler für den +1 Button buttonPlusOne.addEventListener("click", () => { counter++; }); // Event Handler für den -1 Button buttonMinusOne.addEventListener("click", () => { if (counter > 0) { counter--; } }); // Event Handler für den Start/Stop-Button buttonStartStop.addEventListener("click", () => { running = !running; if (running) lastUpdate = Date.now(); }); // Funktion, die kontinuierlich die Anzeige aktualisiert // und jede Sekunde den Zähler runterzählt, wenn die Stoppuhr läuft let updateDisplay = () => { // Jede Sekunde den Zähler runterzählen let now = Date.now(); if (now - lastUpdate >= 1000) { lastUpdate = now; if (running && counter > 0) { counter--; } else { running = false; } } // Aktuellen Status der Stoppuhr anzeigen counterElement.textContent = counter; if (running) { statusElement.textContent = "Uhr läuft …"; } else { statusElement.textContent = "Gestoppt"; } // Sicherstellen, dass die Funktion kontinuierlich aufgerufen wird window.requestAnimationFrame(updateDisplay); }; window.requestAnimationFrame(updateDisplay); });

Änderungen an der DOM-Struktur vornehmen

Die Struktur des Document Object Model kann jederzeit verändert werden.
Der Browser stellt die Änderungen sofort auf dem Bildschirm dar.

Das Aussehen eines Elements verändern

mainElement.style.display = "block";
mainElement.style.marginTop = "1em";

Jedes HTML-Element besitzt in JavaScript das Attribut style zur direkten Beeinflussung seiner Darstellung. Das style-Attribut besitzt für jede CSS-Anweisung ein Unterelement, mit dem Wert der entsprechenden Anweisung ausgelesen oder überschrieben werden kann.

CSS-Anweisungen, die im Stylesheet mit Bindestrich geschrieben werden (zum Beispiel font-size), werden in JavaScript zusammen als „Camel Case„ geschrieben (also fontSize).

alertElement.classList.add("visible");
alertElement.classList.remove("warning");
if (alertElement.classList.contains("fade-in")) { … }

Nicht nur innerhalb des HTML-Codes können jedem Element beliebig viele Klasse zugeordnet werden (über das class-Attribut, zum Beispiel so: <div class="container blue-background"). Dasselbe geht auch über das classList-Attribut in JavaScript. Es handelt sich dabei um ein Objekt mit den oben gezeigten Methoden, um weitere Klassen hinzuzufügen, zu entfernen oder zu prüfen, ob sie vorhanden sind.

Im Zusammenhang mit einem guten CSS-Stylesheet ist diese Variante der direkten Manipulation des style-Attributs vorzuziehen. Denn nach jeder Änderung der classList wertet der Browser die Stylesheets neu aus und macht sich ergebende Änderungen an der Darstellung sofort sichtbar. Auf wunsch sogar animiert, wenn das Stylesheet die transition- oder animation-Anweisung enthält.

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Aussehen verändern mit JavaScript</title> <style> img { display: block; width: 24em; transition: width 0.5s; padding: 0.25em; background: #F0F0F0; border: 1px solid #A0A0A0; margin-bottom: 1em; } body { transition: background-color 0.5s, color 0.5s; } body.dark { background: black; color: white; } body.dark img { background: #A0A0A0; border-color: white; } </style> </head> <body> <h1>Aussehen verändern mit JavaScript</h1> <img src="img/preview1.jpg" /> <button onclick="resizeImage(2)">Größer</button> <button onclick="resizeImage(-2)">Kleiner</button> <button onclick="toggleBackground(event)">Licht aus!</button> <script> // Am Anfang ist das Bild laut Stylesheet 24em breit let width = 24; // Funktion zum Vergrößern oder Verkleinern des Bilds let resizeImage = delta => { width += delta; width = Math.max(width, 10); let imageElement = document.querySelector("img"); imageElement.style.width = width + "em"; }; // Funktion zum Umschalten des Hintergrunds let toggleBackground = event => { let bodyElement = document.querySelector("body"); if (bodyElement.classList.contains("dark")) { bodyElement.classList.remove("dark"); event.target.textContent = "Licht aus!"; } else { bodyElement.classList.add("dark"); event.target.textContent = "Licht an!"; } }; </script> </body> </html>

Aussehen verändern mit JavaScript

Den Inhalt eines Elements überschreiben

alertElement.innerHTML = "<b>Wichtige Frage:</b> Kennen Sie schon unsere Sparangebote?"

Die einfachste Art, den Inhalt eines Elements zu verändern, ist seinem innerHTML-Attribut einen neuen Wert zuzuweisen. Dadurch wird der Inhalt des Elements so verändert, als stünde der neue Wert innerhalb des Elements direkt im HTML-Code. Auf diese Weise können daher auch weitere HTML-Elemente in die Seite eingefügt werden.

Aus Sicherheitsgründen sollte man aber aufpassen, wie sich der neue Wert für innerHTML zusammensetzt. Werden dabei Inhalte von nicht vertrauenswürdigen Quellen zugelassen (zum Beispiel Benutzereingaben), kann dies eine DOM-based Cross Site Scripting-Lücke verursachen. 😔

alertElement.textContent = "Bitte akzeptieren Sie erst die AGBs.";

Bist du dir sicher, dass der neue Inhalt eines Elements keine HTML-Anweisungen beinhalten darf, solltest du anstelle von innerHTML das textContent-Attribut verwenden. Denn hier werden alle spitzen Klammern als Text interpretiert und genau so auf der Seite angezeigt. Die Gefahr für Sicherheitslücken ist dadurch deutlich geringer.

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Inhalte verändern mit JavaScript</title> <style> #preview { display: inline-block; margin-bottom: 1em; border: 1px solid black; padding: 0.25em; background: #303030; color: #87AE87; } </style> </head> <body> <h1>Inhalte verändern mit JavaScript</h1> <div id="preview"></div> <br /> <button onclick="setInnerHtml()">innerHTML setzen</button> <button onclick="setTextContent()">textContent setzen</button> <button onclick="clearPreview()">Vorschau zurücksetzen</button> <script> let previewElement = document.getElementById("preview"); let newContent = "<ol>\n" + " <li>Asterix der Galier</li>" + " <li>Asterix und Kleopatra</li>" + " <li>Asterix erobert Rom</li>" + " <li>Asterix - Sieg über Cäsar</li>" + " <li>Asterix bei den Briten</li>" + " <li>Asterix - Operation Hinkelstein</li>" + " <li>Asterix in Amerika</li>" + " <li>Asterix und die Wikinger</li>" + " <li>Asterix im Land der Götter</li>" + "</ol>\n"; let setInnerHtml = () => previewElement.innerHTML = newContent; let setTextContent = () => previewElement.textContent = newContent; let clearPreview = () => previewElement.innerHTML = ""; </script> </body> </html>

Inhalte verändern mit JavaScript


Größere Änderungen an der DOM-Struktur

let pElement = document.createElement("p");
let pContent = document.createTextNode("Es war einmal vor langer, langer Zeit …");

Auf hoch offiziellem Wege, ohne dabei die Attribute innerHTML und textContent zu benutzen, neue Elemente erzeugen kannst du mit diesen beiden Methoden. Sie erzeugen ein neues HTML-Element bzw. einen Textknoten (enthält nur Text ohne HTML-Code), die du in das Document Object Model einfügen kannst, um sie anzuzeigen.

pElement.appendChild(pContent);

Jedes Element besitzt daher die Methode appendChild, mit der ihm weitere Unterelemente hinzugefügt werden können. Handelt es sich dabei um bereits vorhandene Elemente, die schon im Dokument vorhanden sind, müssen sie erst aus dem Dokument entfernt werden, bevor sie neu eingefügt werden können.

let pElement = pContent.parentNode;

Über das Attribut parentNode kommt man immer von einem Element zu seinem übergeordneten Elternelement.

h1Element = mainElement.childNodes[0];
mainElement.childNodes.forEach(child => …);

Und hier siehst du, wie du auf die Kindelemente eines HTML-Elements zugreifen kannst. Hier gilt wieder, dass es sich bei childNodes um ein NodeList-Objekt und nicht um ein vollwertiges Array handelt.

pElement.removeChild(pContent);

Und last but not least, haben wir hier ein wunderschönes Exemplar der removeChild-Methode. Wie der Name bereits sagt, wird damit ein Element aus der DOM-Struktur entfernt. Dementsprechend verschwindet es dann auch vom Bildschirm und kann bei Bedarf an anderer Stelle wieder eingefügt werden.

Kennst du nur das Element selbst, dass du entfernen willst (hier pElement), kannst du es über folgendem Umweg entfernen:

pElemenet.parentNode.removeChild(pElement);

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Die DOM-Objektstruktur bearbeiten</title> <style> #preview > div { display: inline-block; border: 1px solid #A0A0A0; background: #F0F0F0; padding: 0.3em; box-shadow: 2px 2px 4px rgba(0,0,0,0.4); margin-right: 1em; margin-bottom: 1em; } #preview > div:last-child { margin-right: 0; } #preview > div > img { display: block; } </style> </head> <body> <h1>Die DOM-Objektstruktur bearbeiten</h1> <div id="preview"></div> <div id="html-code"></div> <br /> <button onclick="createContent()">Inhalt generieren</button> <button onclick="removeContent()">Inhalt verwerfen</button> <script> let previewElement = document.getElementById("preview"); let htmlCodeElement = document.getElementById("html-code"); let images = [ {src: "img/preview1.jpg", text: "Küste in Egmont, British Columbia"}, {src: "img/preview2.jpg", text: "Boote an der Küste Egmonts"}, {src: "img/preview3.jpg", text: "Kajaks auf dem Skookumchuk in Egmont"}, ]; // Funktion zum Generieren der Inhalte let createContent = () => { // Alten Inhalt entfernen removeContent(); // Bilder mit Beschreibung einfügen images.forEach(image => { let divElement = document.createElement("div"); previewElement.appendChild(divElement); let imgElement = document.createElement("img"); imgElement.src = image.src; divElement.appendChild(imgElement); let txtNode = document.createTextNode(image.text); divElement.appendChild(txtNode); }); // Generierten HTML-Code anzeigen htmlCodeElement.innerHTML = "Erzeugter HTML-Code:<br />"; let preElement = document.createElement("pre"); htmlCodeElement.appendChild(preElement); let textNode = document.createTextNode(previewElement.innerHTML); preElement.appendChild(textNode); }; // Funktion zum Entfernen der Inhalte let removeContent = () => { previewElement.innerHTML = ""; htmlCodeElement.innerHTML = ""; }; </script> </body> </html>

Die DOM-Objektstruktur bearbeiten


Beispiel: Tabreiter umschalten

DER HUND

Der beste Freund des Menschen

  • Über den Haushund
  • Hunderassen
  • Ernährung

Wie der Mensch, so der Hund

Der Haushund (Canis lupus familiaris) ist ein Haustier und wird als Heim- und Nutztier gehalten. Seine wilde Stammform ist der Wolf, dem er als Unterart zugeordnet wird. Wann die Domestizierung stattfand, ist umstritten; wissenschaftliche Schätzungen variieren zwischen 15.000 und 100.000 Jahren vor unserer Zeit.

Im engeren Sinn bezeichnet man als Haushund die Hunde, die überwiegend im Haus gehalten werden, und kennzeichnet damit also eine Haltungsform. Historisch wurde ein Hund, der zur Bewachung des Hauses gehalten wird, als Haushund bezeichnet. Eine weitere Verwendung des Begriffs ist die Einschränkung auf sozialisierte (Haus-)Hunde, also Hunde, die an das Zusammenleben mit Menschen in der menschlichen Gesellschaft gewöhnt und an dieses angepasst sind. Damit wird der Haushund abgegrenzt gegen wild lebende, verwilderte oder streunende Hunde, die zwar auch domestiziert, aber nicht sozialisiert sind.

Der Dingo ist ebenfalls ein Haushund, wird jedoch provisorisch als eigenständige Unterart des Wolfes geführt.

Weitere Informationen

Einige Hunderassen

Zu den kleinsten anerkannten Hunderassen gehört der Chihuahua (FCI-Nr. 218) mit einem Gewicht von 0,5 bis 3,0 kg und einer Widerristhöhe von unter 20 cm; zu den größten Hunderassen zählen die Deutsche Dogge (FCI-Nr. 235) mit einer Widerristhöhe von mindestens 80 cm bei Rüden und der Irish Wolfhound (FCI-Nr. 160) mit bis zu 95 cm. Zu den seltenen Rassen zählt der Curly Coated Retriever oder auch der aus chinesischer Abstammung hervorgehende und seit mehr als 2000 Jahren dokumentierte Shar Pei.

Die richtige Ernährung ist wichtig

Hunde sind, wie Wölfe, in der Lage, ihre Ernährung in Grenzen an das Nahrungsangebot anzupassen. Schon Wölfe ernähren sich nicht ausschließlich von Beutetieren (wobei diese, weitgehend vollständig gefressen, bereits pflanzliche Nährstoffe enthalten), sondern fressen – je nach Futterangebot – auch pflanzliche Nahrung wie Wurzeln, Blätter, Gräser oder Früchte. Im Verlaufe seines Zusammenlebens mit dem Menschen hat sich der Hund zunehmend an dessen Ernährung angepasst und wurde zum Allesfresser. Fleisch als alleiniges Futtermittel für Hunde ist daher unangemessen.

Eine vollwertige Ernährung der Hunde erfolgt am einfachsten mit qualitativ hochwertigem (industriell gefertigtem) Hundefutter. Diese Fütterung versorgt die Tiere mit allen essentiellen Nahrungsbestandteilen. Manche Hundehalter praktizieren eine Hundeernährung mit spezieller Frischkost (BARF). Ernährungsphysiologisch fragwürdig ist die Ernährung mit Speiseresten, da sie Mangelzustände bewirken kann.

Viele menschliche Nahrungs- und Genussmittel sind für Hunde mehr oder wenig giftig, so zum Beispiel Schokolade aufgrund des enthaltenen Theobromins, aber auch Speisezwiebeln, Weintrauben und Rosinen.

Jetzt Hundefutter kaufen
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>🐶 Tabreiter nachbauen mit JavaScript</title> <link rel="stylesheet" href="common.css" /> <link rel="stylesheet" href="tabpages.css" /> <script src="tabpages.js"></script> </head> <body> <header> <div class="container padding-1"> <h1>DER HUND</h1> <h2>Der beste Freund des Menschen</h2> <ul class="tab-items"> <!-- Lasche 1: Über den Haushund --> <li class="tab-item active" data-tab-content="#tabpage-1"> Über den Haushund <div class="tab-indicator"></div> </li> <!-- Lasche 2: Hunderassen --> <li class="tab-item" data-tab-content="#tabpage-2"> Hunderassen <div class="tab-indicator"></div> </li> <!-- Lasche 3: Ernährung --> <li class="tab-item" data-tab-content="#tabpage-3"> Ernährung <div class="tab-indicator"></div> </li> </ul> </div> </header> <main> <div class="container padding-1"> <!-- Erste Seite: Über den Haushund --> <div id="tabpage-1" class="tab-page"> <h2>Wie der Mensch, so der Hund</h2> <p> Der Haushund (Canis lupus familiaris) ist … </p> <a class="button" href="#"> Weitere Informationen </a> </div> <!-- Zweite Seite: Hunderassen --> <div id="tabpage-2" class="tab-page"> <h2>Einige Hunderassen</h2> <p> Zu den kleinsten anerkannten Hunderassen gehört … </p> </div> <!-- Dritte Seite: Ernährung --> <div id="tabpage-3" class="tab-page"> <h2>Die richtige Ernährung ist wichtig</h2> <p> Hunde sind, wie Wölfe, in der Lage, … </p> <a class="button" href="#"> Jetzt Hundefutter kaufen </a> </div> </div> </main> </body> </html>
html, body { font-family: sans-serif; font-size: 12pt; margin: 0; padding: 0; } header { background-image: url(img/header.jpg); background-repeat: no-repeat; background-position: center center; background-size: cover; padding-bottom: 7%; position: relative; } header .tab-items { position: absolute; bottom: 0; } header h1, header h2 { margin: 0; color: white; } .container { width: 100%; max-width: 70em; margin: 0 auto; } .padding-1 { padding: 1em; } .button { display: inline-block; background-color: darkred; transition: background-color 0.1s; color: white; text-decoration: none; font-weight: bold; padding: 0.75em; } .button:hover { background-color: #c70000; }
/* Container mit den Tablaschen */ .tab-items { list-style: none; padding: 0; margin: 0; } /* Eine einzelne Tablasche */ .tab-item { display: block; margin: 0; padding: 0.75em; min-width: 10em; background: black; border: 0px solid grey; border-bottom-width: 1px; text-transform: uppercase; cursor: pointer; } .tab-item, .tab-item a, .tab-item a:visited { color: #d0d0d0; text-decoration: none; } .tab-item:last-child { border-bottom-width: 0; border-right-width: 0; } @media all and (min-width: 30em) { .tab-items { display: flex; } .tab-item { border-bottom-width: 0; border-right-width: 1px; } } .tab-item:hover, .tab-item:hover a, .tab-item:hover a:visited { color: white; } .tab-item .tab-indicator { margin-top: 0.5em; width: 3em; height: 0.3em; background-color: #b0b0b0; } .tab-item:hover .tab-indicator { background-color: white; } /* Aktive Tablasche */ .tab-item.active { background: white; font-weight: bold; } .tab-item.active, .tab-item.active a, .tab-item.active a:visited { color: #404040; } .tab-item.active:hover, .tab-item.active:hover a, .tab-item.active:hover a:visited { color: black; } .tab-item.active .tab-indicator { background-color: darkred; } .tab-item.active:hover .tab-indicator { background-color: #c70000; } /* Klasse zum Ausblenden der unsichtbaren Tabreiter */ .tab-page { display: none; }
/** * Hier werden nach dem Laden der Seite alle .tab-items gesucht und mit Event * Handlern zum Umschalten der Tabreiter versehen. Außerdem wird der erste * aktive Tabreiter (gekennzeichnet durch .active) angezeigt. */ window.addEventListener("load", () => { // Funktion zum Umschalten der Tabreiter let switchTabPage = (clickedTabItem) => { // Erst mal alle Tabseiten ausblenden clickedTabItem.parentNode.childNodes.forEach(tabItem => { if (tabItem.nodeType != Node.ELEMENT_NODE) return; tabItem.classList.remove("active"); let tabContent = document.querySelector(tabItem.dataset.tabContent); if (tabContent != null) { tabContent.classList.add("tab-page"); } }); // Dann die ausgewählte Tabseite anzeigen clickedTabItem.classList.add("active"); let tabContent = document.querySelector(clickedTabItem.dataset.tabContent); if (tabContent != null) { tabContent.classList.remove("tab-page"); } } // Alle Tablaschen in der Seite suchen let tabItems = document.querySelectorAll(".tab-item"); // Event Handler registrieren und erste Tabseite anzeigen tabItems.forEach(tabItem => { // Bist du eine aktive Tablasche? Dann Inhalt anzeigen. if (tabItem.classList.contains("active")) { switchTabPage(tabItem); } // Aktive Seite bei Klick auf die Lasche wechseln tabItem.addEventListener("click", event => { switchTabPage(event.target); }); }); });

Bildnachweis: Pixabay: Fran_F, Textnachweis: Wikipedia: Haushund, Layoutidee: RedHat

Beispiel: Formulareingaben überprüfen

Kontaktformular

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Formulareingaben überprüfen</title> <link rel="stylesheet" href="style.css" /> <script src="script.js"></script> </head> <body> <h1>Kontaktformular</h1> <form onsubmit = "validateForm(event)" action = "contact-form.php" method = "POST" > <!-- Vorname und Nachname --> <label for="firstname"> Ihr Name: <span class="required">*</span> </label> <div class="side-by-side"> <input name="firstname" type="text" placeholder="Vorname" /> <input name="lastname" type="text" placeholder="Nachname" /> </div> <!-- E-Mailadresse --> <label for="email"> E-Mail: <span class="required">*</span> </label> <input name="email" type="email" /> <!-- Auswahlliste für den Betreff --> <label for="subject"> Betreff: </label> <select name="subject"> <option selected="selected">Allgemeine Anfrage</option> <option>Angebot aus der Werbung</option> <option>Kooperation und Partnerschaft</option> </select> <!-- Die Nachricht --> <label for="message"> Ihre Nachricht: <span class="required">*</span> </label> <textarea name="message"></textarea> <!-- Button zum Abschicken des Formulars --> <input type="submit" value="Abschicken" /> </form> <!-- Hier wird das Ergebnis der Prüfung angezeigt --> <div id="result"></div> </body> </html>
/* * Allgemeine Angaben */ @import url('https://fonts.googleapis.com/css?family=Quicksand'); html { font-family: 'Quicksand', sans-serif; font-size: 12pt; } /* * Basis-Layout des Formulars */ form { max-width: 30em; border: 1px solid #d0d0d0; background: #f0f0f0; padding: 1em; } form > *, form > .side-by-side > * { display: block; box-sizing: border-box; width: 100%; } form > .side-by-side { display: flex; } form > .side-by-side > * { margin-right: 0.25em; } form > .side-by-side > *:last-child { margin-right: 0; } /* * Gestaltung der Feldbezeichner */ form label { font-weight: bold; margin-top: 1em; } form label:first-child { margin-top: 0; } form label .required { color: darkred; } /* * Gestaltung der Formularfelder */ input, textarea, select { border: 1px solid #bebebe; padding: 0.5em; margin: 0; outline: none; } textarea { height: 12em; } /* * Der Button zum Abschicken des Formulars */ input[type="submit"] { margin-top: 2em; width: auto; background-color: #0958A7; color: white; font-weight: bold; transition: background-color 0.2s; } input[type="submit"]:hover { background-color: #2868A8; } /* * Element mit dem Prüfergebnis */ #result { margin-top: 1em; color: red; } #result.okay { color: darkgreen; }
/** * Funktion zur Überprüfung des Kontaktformulars. Wird beim Abschicken des * Formulars aufgerufen. */ let validateForm = event => { // Variablen für das Prüfergebnis let form = event.target; let okay = true; let message = ""; // Vorname muss vorhanden sein if (form.firstname.value == "") { okay = false; message += "Geben Sie bitte Ihren Vornamen ein. <br />"; } // Nachname muss vorhanden sein if (form.lastname.value == "") { okay = false; message += "Geben Sie bitte Ihren Nachnamen ein. <br />"; } // E-Mail muss vorhanden sein und zusätzlich ein @ enthalten // HINWEIS: Besser wäre es, die E-Mailadresse mit einem regulären // Ausdruck zu prüfen. Einfach mal nach „E-Mail Regex” googlen … if (form.email.value == "" || !form.email.value.includes("@")) { okay = false; message += "Geben Sie bitte eine gültige E-Mailadresse ein. <br />"; } // Eine Nachricht muss vorhanden sein if (form.message.value == "") { okay = false; message += "Geben Sie bitte eine Nachricht ein. <br />"; } // Ergebnis anzeigen let resultElement = document.getElementById("result"); if (okay) { message = "Vielen Dank für Ihre Nachricht!"; resultElement.classList.add("okay"); } else { resultElement.classList.remove("okay"); } resultElement.innerHTML = message; // Formular nicht abschicken //if (!okay) { event.preventDefault(); //} }

Aufgabe 8: Ein kleines DOM-Quiz

Aufgabe 8.1: HTML-Elemente auslesen

a) Welche Methode liefert alle Elemente mit derselben Klasse?

  1. document.getElementsByName("…")
  2. document.getElementsByClassName("…")
  3. document.getElementById("…")

b) Welche Methoden liefern das Element mit der ID „toolbar” zurück?

  1. document.getElementById("toolbar")
  2. document.querySelector("toolbar")
  3. document.querySelector("#toolbar")
  4. document.querySelectorAll("toolbar")
  5. document.querySelectorAll("#toolbar")

c) Was liefert die Methode document.getElementById als Ergebnis, wenn das gesuchte Element nicht gefunden wurde?

  1. false
  2. undefined
  3. null

d) Was liefert die Methode document.querySelectorAll als Ergebnis, wenn die gesuchten Elemente nicht gefunden wurden?

  1. Nichts
  2. Eine leere Menge mit 0 Einträgen
  3. Den Wert false
  4. Die Zahl 0

Aufgabe 8.2: Inhalte verändern und erzeugen

a) Wie kann die CSS-Eigenschaft „border-bottom-width” eines HTML-Elements mit JavaScript verändert werden?

  1. element.style.set("border-bottom-widht", "1px")
  2. element.style.border-bottom-width = "1px"
  3. element.style.border_bottom_width = "1px"
  4. element.style.borderBottomWidth = "1px"
  5. element.style["borderBottomWidth"] = "1px"

b) Wie kann einem HTML-Element die Klasse „invisible” hinzugefügt werden?

  1. document.classListAdd("invisible")
  2. element.classList.add("invisible")
  3. element.classList.invisible = true
  4. element.styleList.add("invisible")
  5. element.style.invisible = true

c) Was passiert, wenn man dem Attribut innerHTML einen String mit Text und HTML-Elementen übergibgt?

  1. Der Text wird genau so angezeigt, wie er übergeben wurde. Die sptizen Klammern werden auf dem Bildschirm angezeigt.
  2. Der Text wird genau so angezeigt, wie er übergeben wurde, jedoch werden alle spitzen Klammern entfernt.
  3. Der Text wird als HTML-Code interpretiert. Auf dem Bildschirm sieht man daher das Ergebnis der HTML-Elemente. Ganz so, als wären sie von Anfang an im Quellcode der Seite gestanden.

d) Was passiert, wenn man dem Attribut textContent einen String mit Text und HTML-Elementen übergibgt?

  1. Der Text wird genau so angezeigt, wie er übergeben wurde. Die sptizen Klammern werden auf dem Bildschirm angezeigt.
  2. Der Text wird genau so angezeigt, wie er übergeben wurde, jedoch werden alle spitzen Klammern entfernt.
  3. Der Text wird als HTML-Code interpretiert. Auf dem Bildschirm sieht man daher das Ergebnis der HTML-Elemente. Ganz so, als wären sie von Anfang an im Quellcode der Seite gestanden.

Aufgabe 8.3: Arbeiten mit der DOM-Struktur

a) Mit welchem Attribut kann auf das Elternelement eines HTML-Elements zugegriffen werden?

  1. element.p
  2. element.parent
  3. element.parentNode
  4. element.parentNodes

b) Wie kann ein Element aus dem DOM-Baum entfernt werden?

  1. element.remove()
  2. element.discard()
  3. element.parentNode.removeChild()
  4. element.parentNode.removeChild(element)

c) Welcher Aufruf erzeugt ein neues <div>-Element?

  1. document.createElement("div")
  2. document.createElement("<div>")
  3. document.createHtml("<div>")
  4. document.createTextNode("div")

d) Welcher Aufruf fügt ein neues Element in den DOM-Baum ein?

  1. document.insert(element)
  2. document.append(element)
  3. element1.insertChild(element1, element2)
  4. element1.appendChild(element2)

Lösung: Aufgabe 8.1: 1, 1+3, 3, 2; Aufgabe 8.2: 4+5, 2, 3, 1; Aufgabe 8.3: 3, 4, 1, 4

Aufgabe 9: Formularprüfung

Lade dir den Quellcode zu dieser Aufgabe herunter und passe das in der Seite enthaltene Formular wie folgt an:

  1. Alle mit einem roten Stern markierten Felder sind Pflichtfelder. Das Formular soll sich nicht abschicken lassen, so lange eines dieser Felder leer oder fehlerhaft ist.
  2. Die Daten für den zweiten Reisenden sollen nur geprüft werden, wenn entweder sein Vor- oder sein Nachname eingegeben wurde.
  3. Das Anreisedatum und das Abreisedatum sollen ebenfalls Pflichtfelder sein.
  4. Jede E-Mailadresse muss mindestens ein @-Zeichen enthalten.

Das Ergebnis der Prüfung soll unterhalb des Formulars angezeigt werden. Bei Erfolg, soll die Schrift grün und bei Fehlern soll sie rot sein.

Anpassungen am HTML-Quellcode

Im <head> muss eine neue JavaScript-Datei eingebunden werden:

<head> <meta charset="utf-8" /> <title>Hotelreservierung buchen</title> <link rel="stylesheet" href="style.css" /> <script src="script.js"></script> </head>

Das Formular muss um einen onsubmit-Handler erweitert werden:

<form onsubmit = "validateForm(event)" action = "hotel-booking.php" method = "POST" > … </form>

JavaScript-Code

In der neuen JavaScript-Datei wird folgender Quellcode benötigt:

/** * Funktion zur Überprüfung des Kontaktformulars. Wird beim Abschicken des * Formulars aufgerufen. */ let validateForm = event => { // Variablen für das Prüfergebnis let form = event.target; let okay = true; let message = ""; // Erster Reisender if (form.first_firstname.value == "") { okay = false; message += "Geben Sie bitte den Vornamen des ersten Reisenden ein. <br />"; } if (form.first_lastname.value == "") { okay = false; message += "Geben Sie bitte den Nachnamen des ersten Reisenden ein. <br />"; } if (form.first_zip.value == "") { okay = false; message += "Geben Sie bitte die Postleitzahl des ersten Reisenden ein. <br />"; } if (form.first_city.value == "") { okay = false; message += "Geben Sie bitte den Ort des ersten Reisenden ein. <br />"; } if (form.first_country.value == "") { okay = false; message += "Geben Sie bitte das Land des ersten Reisenden ein. <br />"; } if (form.first_email.value == "" || !form.first_email.value.includes("@")) { okay = false; message += "Geben Sie bitte eine gültige E-Mailadresse ein. <br />"; } // Zweiter Reisender if (form.second_firstname.value != "" || form.second_lastname.value != "") { if (form.second_firstname.value == "") { okay = false; message += "Geben Sie bitte den Vornamen des zweiten Reisenden ein. <br />"; } if (form.second_lastname.value == "") { okay = false; message += "Geben Sie bitte den Nachnamen des zweiten Reisenden ein. <br />"; } if (form.second_zip.value == "") { okay = false; message += "Geben Sie bitte die Postleitzahl des zweiten Reisenden ein. <br />"; } if (form.second_city.value == "") { okay = false; message += "Geben Sie bitte den Ort des zweiten Reisenden ein. <br />"; } if (form.second_country.value == "") { okay = false; message += "Geben Sie bitte das Land des zweiten Reisenden ein. <br />"; } if (form.second_email.value != "" && !form.second_email.value.includes("@")) { okay = false; message += "Geben Sie bitte eine gültige E-Mailadresse ein. <br />"; } } // Ankunft und Abreise if (form.arrival.value == "") { okay = false; message += "Geben Sie bitte das Ankunftsdatum ein. <br />"; } if (form.departure.value == "") { okay = false; message += "Geben Sie bitte das Abreisedatum ein. <br />"; } // Ergebnis anzeigen let resultElement = document.getElementById("result"); if (okay) { message = "Vielen Dank für Ihre Nachricht!"; resultElement.classList.add("okay"); } else { resultElement.classList.remove("okay"); } resultElement.innerHTML = message; // Formular nicht abschicken //if (!okay) { event.preventDefault(); //} }

Aufgabe 10: TODO-Liste

Lade dir den Quellcode zu dieser Aufgabe herunter und schaue ihn dir an. Es handelt sich dabei um eine einfache TODO-Liste mit nur zwei Funktionen: Einträge hinzufügen und Einträge löschen. Der Quellcode ist auch schon fast fertig. Es fehlen nur noch ein paar Kleinigkeiten:

  1. Im HTML-Code findest du zwischen den Kommentaren ein Beispiel für eine Notiz. Das Beispiel soll dir als Vorlage für den JavaScript-Code dienen, muss aus dem HTML aber ausgebaut werden.
  2. Im JavaScript-Code musst du stattdessen die insertMemo-Funktion so ausprogrammieren, dass sie die Seite nach dem vorgegebenen Beispiel erweitert, um ein neues Memo anzuzeigen.
  3. Jedes Memo soll einen Link zum Entfernen des Memos besitzen.
  4. Beim Start der Anwendung soll automatisch ein Beispielmemo angelegt werden.

Anpassungen am HTML-Code

Im HTML-Code muss lediglich die Beispielnotiz entfernt werden. Der <body> sieht danach daher so aus:

<body> <div id="toolbar"> <button id="button-new"> Neue Notiz anlegen </button> </div> <main> <ul></ul> </main> </body>

Anpassungen am JavaScript-Code

Die insertMemo-Funktion muss wie folgt ausprogrammiert werden:

let insertMemo = text => { let liElement = document.createElement("li"); memoList.appendChild(liElement); let memoTextElement = document.createElement("p"); memoTextElement.textContent = text; liElement.appendChild(memoTextElement); let deleteElement = document.createElement("a"); deleteElement.textContent = "Löschen"; deleteElement.classList.add("delete"); liElement.appendChild(deleteElement); deleteElement.addEventListener("click", () => { liElement.parentNode.removeChild(liElement); }); };

Eine neue Beispielnotiz lässt sich mit folgendem Aufruf erzeugen:

insertMemo("Klicke auf „Neue Notiz”, um eine neue Notiz anzulegen …");

Hinweise zum Schluss

Bildnachweis: Pixabay: rawpixel

Do & Don't

Grundregeln für guten JavaScript-Code

DOM-Manipulation mit JavaScript

Nützliche Werkzeuge

Rechtshinweise

Creative Commons Namensnennung 4.0 International

§