|
| 1 | +--- |
| 2 | +title: Zähler |
| 3 | +order: 5 |
| 4 | +--- |
| 5 | + |
| 6 | +Ein einfacher Zähler |
| 7 | +------------------- |
| 8 | + |
| 9 | +An diesem Simplen Beispiel werden wir verschiedene |
| 10 | +Arten Javascript zu schreiben kennen lernen. |
| 11 | + |
| 12 | +Hier ist die Ausgangsversion des Codes: |
| 13 | + |
| 14 | + |
| 15 | +<htmlcode> |
| 16 | +<input type="number" id="counter" value="0"> |
| 17 | +<button onclick="increment()">Up</button> |
| 18 | +<button onclick="decrement()">Down</button> |
| 19 | + |
| 20 | +<script> |
| 21 | + function increment() { |
| 22 | + const counter = document.getElementById('counter'); |
| 23 | + counter.value = parseInt(counter.value) + 1; |
| 24 | + } |
| 25 | + |
| 26 | + function decrement() { |
| 27 | + const counter = document.getElementById('counter'); |
| 28 | + counter.value = parseInt(counter.value) - 1; |
| 29 | + } |
| 30 | +</script> |
| 31 | +</htmlcode> |
| 32 | + |
| 33 | + |
| 34 | +## addEventListener |
| 35 | + |
| 36 | +Die Event-Listener sind als `onclick` Attribute in HTML gesetzt. |
| 37 | +Das kann man auch ganz von JavaScript aus machen, mit `addEventListener`. |
| 38 | +Dann hat man in HTML nur noch die Aufgabe die verschiednenen Elemente |
| 39 | +mit eindeutigen id's oder Klassen zu benennen. Alles weitere passiert in Javascript: |
| 40 | + |
| 41 | +<htmlcode> |
| 42 | +<input type="number" id="counter" value="0"> |
| 43 | +<button id="up">Up</button> |
| 44 | +<button id="down">Down</button> |
| 45 | + |
| 46 | +<script> |
| 47 | + const counter = document.getElementById('counter'); |
| 48 | + const upButton = document.getElementById('up'); |
| 49 | + const downButton = document.getElementById('down'); |
| 50 | + |
| 51 | + function increment() { |
| 52 | + counter.value = parseInt(counter.value) + 1; |
| 53 | + } |
| 54 | + |
| 55 | + function decrement() { |
| 56 | + counter.value = parseInt(counter.value) - 1; |
| 57 | + } |
| 58 | + |
| 59 | + upButton.addEventListener('click', increment); |
| 60 | + downButton.addEventListener('click', decrement); |
| 61 | +</script> |
| 62 | +</htmlcode> |
| 63 | + |
| 64 | +## Problemt mit der DOM |
| 65 | + |
| 66 | +Achtung: wenn man das Javascript **vor** dem HTML in die |
| 67 | +Seite gibt, hat man ein Problem: |
| 68 | + |
| 69 | +<htmlcode> |
| 70 | +<head> |
| 71 | + <title>Simple Counter</title> |
| 72 | + <script> |
| 73 | + const counter = document.getElementById('counter'); |
| 74 | + const upButton = document.getElementById('up'); |
| 75 | + const downButton = document.getElementById('down'); |
| 76 | + |
| 77 | + function increment() { |
| 78 | + counter.value = parseInt(counter.value) + 1; |
| 79 | + } |
| 80 | + |
| 81 | + function decrement() { |
| 82 | + counter.value = parseInt(counter.value) - 1; |
| 83 | + } |
| 84 | + |
| 85 | + upButton.addEventListener('click', increment); |
| 86 | + downButton.addEventListener('click', decrement); |
| 87 | + </script> |
| 88 | +</head> |
| 89 | +<body> |
| 90 | + <input type="number" id="counter" value="0"> |
| 91 | + <button id="up">Up</button> |
| 92 | + <button id="down">Down</button> |
| 93 | +</body> |
| 94 | +</htmlcode> |
| 95 | + |
| 96 | +Der Counter funktioniert nicht mehr, und in der Console sieht man die Fehlermeldung: |
| 97 | + |
| 98 | +**Uncaught TypeError: can't access property "addEventListener", upButton is null** |
| 99 | + |
| 100 | +Das Problem ist, dass der upButton noch gar nicht existiert, wenn der Code |
| 101 | +ausgeführt wird. `document.getElementById('up')` liefert dann den wert `null`, |
| 102 | +mit dem wir aber nicht weiter arbeiten können. |
| 103 | + |
| 104 | +## Lösung DOMContentLoaded |
| 105 | + |
| 106 | +Das Event `DOMContentLoaded` wird gefeuert, wenn die DOM vollständig |
| 107 | +ist: |
| 108 | + |
| 109 | +<htmlcode> |
| 110 | +document.addEventListener('DOMContentLoaded', setupCounter); |
| 111 | +</htmlcode> |
| 112 | + |
| 113 | +Die Funktion `setupCounter` müssen wir nur zuerst definieren, |
| 114 | +so sieht also das gesamte Beispiel aus: |
| 115 | + |
| 116 | +<htmlcode> |
| 117 | +function setupCounter() { |
| 118 | + const counter = document.getElementById('counter'); |
| 119 | + const upButton = document.getElementById('up'); |
| 120 | + const downButton = document.getElementById('down'); |
| 121 | + |
| 122 | + function increment() { |
| 123 | + counter.value = parseInt(counter.value) + 1; |
| 124 | + } |
| 125 | + |
| 126 | + function decrement() { |
| 127 | + counter.value = parseInt(counter.value) - 1; |
| 128 | + } |
| 129 | + |
| 130 | + upButton.addEventListener('click', increment); |
| 131 | + downButton.addEventListener('click', decrement); |
| 132 | +} |
| 133 | + |
| 134 | +document.addEventListener('DOMContentLoaded', setupCounter); |
| 135 | +</htmlcode> |
| 136 | + |
| 137 | +## Javascript Klasse |
| 138 | + |
| 139 | +Bisher ist der Wert des Zählers direkt im DOM-Element gespeichert. |
| 140 | +Bei komplexeren Beispielen wollen wir das sicher nicht mehr, da wollen |
| 141 | +wir Javascript Klassen verwenden. |
| 142 | + |
| 143 | +Wir können also ein Klasse für den Zähler programmieren: |
| 144 | + |
| 145 | +<javascript> |
| 146 | +class Counter { |
| 147 | + constructor(initialValue = 0) { |
| 148 | + this.value = initialValue; |
| 149 | + } |
| 150 | + |
| 151 | + increment() { |
| 152 | + this.value++; |
| 153 | + this.updateDisplay(); |
| 154 | + } |
| 155 | + |
| 156 | + decrement() { |
| 157 | + this.value--; |
| 158 | + this.updateDisplay(); |
| 159 | + } |
| 160 | + |
| 161 | + updateDisplay() { |
| 162 | + document.getElementById('counter').value = this.value; |
| 163 | + } |
| 164 | +} |
| 165 | +</javascript> |
| 166 | + |
| 167 | +### Erzeugen des Objekts und Anbindung an die DOM |
| 168 | + |
| 169 | +In der setup-Funktion wird nun ein Objekt dieser Klasse |
| 170 | +erzeugt: |
| 171 | + |
| 172 | +<javascript> |
| 173 | +function setupCounter() { |
| 174 | + const counter = new Counter(0); |
| 175 | + const upButton = document.getElementById('up'); |
| 176 | + const downButton = document.getElementById('down'); |
| 177 | + |
| 178 | + upButton.addEventListener('click', counter.increment()); |
| 179 | + downButton.addEventListener('click', counter.decrement()); |
| 180 | +} |
| 181 | + |
| 182 | +document.addEventListener('DOMContentLoaded', setupCounter); |
| 183 | +</javascript caption="mit Fehler"> |
| 184 | + |
| 185 | +Aber Achtung: dieser Code funktioniert nicht! |
| 186 | + |
| 187 | +### EventListener richtig aufsetzen |
| 188 | + |
| 189 | +Das Problem sind diese beiden Zeilen: |
| 190 | + |
| 191 | +<javascript> |
| 192 | +upButton.addEventListener('click', counter.increment()); // FALSCH! |
| 193 | +downButton.addEventListener('click', counter.decrement()); // FALSCH! |
| 194 | +</javascript> |
| 195 | + |
| 196 | +Wenn `addEventListener` ausgeführt wird, wird die Methode `counter.increment` |
| 197 | +einmal aufgerufen. Sie liefert keinen Rückgabewert, also `undefined`. |
| 198 | +Damit passiert dann bei jedem klick auf den Button ... nichts! |
| 199 | + |
| 200 | +Zweiter Versuch: |
| 201 | + |
| 202 | +<javascript> |
| 203 | +upButton.addEventListener('click', counter.increment); // FALSCH! |
| 204 | +downButton.addEventListener('click', counter.decrement); // FALSCH! |
| 205 | +</javascript> |
| 206 | + |
| 207 | +Auch hier gibt es einen Error: **Uncaught TypeError: this.updateDisplay is not a function**. |
| 208 | +Hier funktioniert zwar der Aufruf der Methode, aber die Methode erhält |
| 209 | +als `this` eine referenz auf den geklickten Button. Diese setzen von `this` |
| 210 | +bei `addEventListener` gab es schon, bevor es Klassen gab. Heute ist |
| 211 | +es sehr unpraktisch. |
| 212 | + |
| 213 | + |
| 214 | +Um das Problem zu umgehen kann man eine Arrow Funkction verwenden, |
| 215 | +dann klappts auch mit dem `this`: |
| 216 | + |
| 217 | +<javascript> |
| 218 | +upButton.addEventListener('click', () => counter.increment()); |
| 219 | +downButton.addEventListener('click', () => counter.decrement()); |
| 220 | +</javascript> |
| 221 | + |
| 222 | + |
0 commit comments