đïž Push the Button
đŻ Ziele
Unsere Buttons sehen zwar aus wie Buttons, aber sie machen noch nichts. Wir wollen folgende Funktionen erreichen:
- Artikel Like Button - mit Unlike und ZĂ€hler
- Autor:in Folgen Button - mit Unfollow
- Thema Folgen Button - mit Unfollow
Frontend-Focus: In dieser Umsetzung konzentrieren wir uns auf Frontend-Logik. Daten werden nur im Frontend gespeichert - bei einem Page-Reload werden alle Status zurĂŒckgesetzt.
Skript Setup
Button-Script erstellen
- Neue Datei erstellen:
buttons.jsimjavascriptOrdner - Import in
main.jshinzufĂŒgen - Test mit Console-Output (siehe Kapitel "Table Auto Design")
đ Debugging-Optionen
FĂŒr lokales Debugging siehe:
Event Listener verstehen
Events Grundlagen
Ein Event ist eine Nachricht wenn eine Aktion stattfindet - wie "Button XY wurde gedrĂŒckt". Der Browser kennt Standard-Reaktionen auf Events (z.B. Checkbox an/aus).
Mehr dazu: MDN Event.preventDefault
Events finden
Ăffne fĂŒr mehr Infos
Herausforderung: Nicht jedes Element bietet die selben Events an:
- Button kann geklickt werden
- Textfeld kann beschrieben werden
- Maus kann bewegt werden
Aber wie finde ich heraus, welche Events verfĂŒgbar sind?
MDN-Dokumentation durchsuchen
- Button-spezifische API: HTMLButtonElement
- Instance Methods: HTMLButtonElement#instance_methods
- Problem: Der "click" Event ist hier nicht direkt zu finden!
Vererbungskette verstehen
Wichtiger Hinweis: Button erbt Methoden vom Eltern-Element:
"inherits methods from its parent, HTMLElement"
Lösungsweg: Durch die Vererbungskette navigieren:
HTMLButtonElementâHTMLElementâElement- Ziel: Element API - hier finden sich die meisten Events!
Praktische Tipps
| Methode | Beschreibung | EffektivitÀt |
|---|---|---|
| Dokumentation | MDN systematisch durchsuchen | VollstÀndig aber zeitaufwÀndig |
| Trial & Error | Events ausprobieren und testen | Schnell fĂŒr bekannte Events |
| IDE-Support | Autocomplete und IntelliSense nutzen | Sehr praktisch wÀhrend Entwicklung |
Praxis-Tipp: Die Devise "trial and error" ist oft effizienter als stundenlanges Dokumentation-Studium!
Event Listener erstellen
Schritt 1: Alle Buttons finden und Event Listener registrieren
document.querySelectorAll("button").forEach((button) => {
// FĂŒr jeden Button einen Click-Listener erstellen
});
Event Listener hinzufĂŒgen: MDN addEventListener
button.addEventListener("click", () => {
// Handle button click
});
Der erste Parameter ist der Event Type, der zweite (nach dem ,) nimmt eine Funktion entgegen, welche ausgefĂŒhrt werden soll, wenn der Listener greift. Nun wird es etwas kompliziert, wenn du dies im Detail verstehen möchtest⊠Lies dazu JavaScript und Callbacks oder ĂŒbernimmt einfach mal nachfolgende Code Snippets.
Erster Test
document.querySelectorAll("button").forEach((button) => {
button.addEventListener("click", () => {
// Handle button click
alert(`Button "${button.textContent.trim()}" wurde geklickt!`);
});
});
Teste im Browser - bei jedem Button-Klick sollte ein Alert erscheinen!
HTML mit Data-Attributen erweitern
Button-Unterscheidung
Wir haben 3 verschiedene Button-Typen. FĂŒr bessere JavaScript-Kontrolle erweitern wir das HTML:
Data-Attribute hinzufĂŒgen:
data-button-state: "active" oder "inactive"data-button: Button-Name zur Identifikation
HTML-Updates
Like Button
<button
data-button-state="inactive"
data-button="like_article"
class="primary mb-s font-small align-items-center text-center">
Autor:in folgen
<button
data-button-state="inactive"
data-button="follow_author"
class="primary">
Thema folgen
<button
data-button-state="inactive"
data-button="follow_topic"
class="primary">
Spezifische Button-Auswahl
document.querySelectorAll("button[data-button]").forEach((button) => {
// Nur Buttons mit data-button Attribut
});
Button States Management
⥠Switch-Statement fĂŒr Button-Typen
Siehe auch JavaScript Switch Statement
document.querySelectorAll("button[data-button]").forEach((button) => {
button.addEventListener("click", () => {
switch (button.dataset.button) {
case "like_article":
break;
case "follow_author":
break;
case "follow_topic":
break;
default:
console.warn(`Unbekannter Button-Typ: ${button.dataset.button}`);
}
});
});
Toggle-FunktionalitÀt
Im nĂ€chsten Schritt wollen wir ein einfaches "toggle" einbauen. Das ist der Begriff, wenn zwischen ZustĂ€nden gewechselt wird. Meistens zwischen 2 wie bei uns. Von inaktiv auf aktiv und zurĂŒck.
Toggle-Funktion erstellen:
Damit der Button tatsÀchlich "toggled" wollen wir die Funktion toggleButtonState so erweitern, dass sie den nun aktiven State ausliest und ihn "umdreht". ZusÀtzlich setzen bzw. entfernen wir den primary-button als CSS Klasse. So wird bereits optisch was passieren.
Lies also als erstes den state aus dem Button und speichere ihn als lokale Variable in der Funktion ab.
function toggleButtonState(button) {
const currentState = button.dataset.buttonState;
Nun kannst du mit einem "if" unterscheiden was basierend auf dem aktuellen State passieren soll. Nebst der CSS Klasse setzen wir auch den State zurĂŒck.
function toggleButtonState(button) {
const currentState = button.dataset.buttonState;
if (currentState == "active") {
button.classList.add("primary");
button.dataset.buttonState = "inactive";
} else {
button.classList.remove("primary");
button.dataset.buttonState = "active";
}
}
Funktionsaufruf in Switch-Statement:
Nun muss die Funktion noch aufgerufen werden.
switch (button.dataset.button) {
case "like_article":
toggleButtonState(button);
break;
case "follow_author":
toggleButtonState(button);
break;
case "follow_topic":
toggleButtonState(button);
break;
}
CSS-Klassen automatisch togglen
Mit classList.toggle wird das setzen/entfernen der CSS Klasse noch einfacher:
function toggleButtonState(button) {
const currentState = button.dataset.buttonState;
button.classList.toggle("primary");
if (currentState == "active") {
button.dataset.buttonState = "inactive";
} else {
button.dataset.buttonState = "active";
}
}
Button-Texte dynamisch Àndern
Text-Parameter hinzufĂŒgen
function toggleButtonState(button, activationText, inactivatingText) {
const currentState = button.dataset.buttonState;
button.classList.toggle("primary");
if (currentState == "active") {
button.textContent = activationText;
button.dataset.buttonState = "inactive";
} else {
button.textContent = inactivatingText;
button.dataset.buttonState = "active";
}
}
ErklÀrungen
- mit
.textContenterhalten wir direkt den Text ohne inneres HTML activationTextundinactivatingTextsind zwei neue Funktions Parameter- Die Texte mĂŒssen ĂŒbergeben werden, damit sie was tun
Text-Konstanten definieren
Diese werden am Anfang des Files definiert und erlauben einfaches lesen der Texte.
const likePageText = "Dieser Artikel gefÀllt mir!";
const unlikePageText = "Dieser Artikel gefÀllt mir nicht mehr";
const followAuthorText = "Autor:in folgen";
const unfollowAuthorText = "Autor:in nicht mehr folgen";
const followTopicText = "Thema folgen";
const unfollowTopicText = "Thema entfolgen";
Switch-Statement mit Texten
Damit die Texte stimmen, ĂŒbergibst du sie aus der Switch Funktion an die Toggle Funktion.
switch (button.dataset.button) {
case "like_article":
toggleButtonState(button, likePageText, unlikePageText);
break;
case "follow_author":
toggleButtonState(button, followAuthorText, unfollowAuthorText);
break;
case "follow_topic":
toggleButtonState(button, followTopicText, unfollowTopicText);
break;
}
Like Button erweitern
Like Counter implementieren
Der Like Button braucht zusÀtzliche Features:
- ZĂ€hler fĂŒr Likes
- Icon mit Herz/gebrochenem Herz (Kosmetik)
HTML fĂŒr Counter markieren
Zahl mit span und ID markieren:
Den counter legen wir lokal im JavaScript an, mit dem Bewusstsein, dass die Daten spĂ€ter von einem Server kommen sollten. Dazu mĂŒssen wir zudem im HTML die Stelle markieren, wo der Counter steht.
Gehe zur Stelle im HTML wo steht "59 Personen gefÀllt dieser Artikel".
Wir wollen nur die Zahl steuern können. DafĂŒr ist ein <span> Element perfekt geeignet, da es keine Zeile erstellt. FĂŒge ein span Element um die Zahl ein und vergib die id "data-like-counter".
<span id="data-like-counter">59</span> Personen gefÀllt dieser Artikel
đĄ Wichtig: IDs dĂŒrfen nur einmal pro HTML existieren!
Like-spezifische Toggle-Funktion
Der Like Button wird nun eine Sonderbehandlung brauchen. Lege eine neue Function an im JavaScript und nenne sie toggleLikeButtonState. Als Parameter brauchen wir den Button.
function toggleLikeButtonState(button) {
const currentState = button.dataset.buttonState;
const likeCounter = document.querySelector("#data-like-counter");
// Alternative: document.getElementById("data-like-counter");
let currentCount = parseInt(likeCounter.textContent);
if (currentState == "inactive") {
currentCount++;
} else {
currentCount--;
}
likeCounter.textContent = currentCount;
}
ErklÀrungen
currentCountdient als Zwischenspeicher des aktuellen CountparseIntkonvertiert den Text zu einer Zahl, damit das Rechnen sauber klapptbutton.dataset.buttonStateholt den Wert des Data Attributes mit Namenbutton-state- der
currentStatedient fĂŒr die Unterscheidung, ob plus oder minus gezĂ€hlt wird - mit
likeCounter.textContent =wird der neue Wert gesetzt
Integration mit bestehender Toggle-Logik
Handelt es sich um den Like Button, soll die neue Logik aufgerufen werden.
case "like_article":
toggleLikeButtonState(button, likePageText, unlikePageText);
break;
Text und Aussehen korrigieren
Wenn du jetzt ausprobierst, was passiert, wirst du bemerken, dass zwar der ZĂ€hler funktioniert, dafĂŒr aber der Text und Aussehen nicht mehr stimmen. Das gute ist, die Logik haben wir ja bereits im "toggleButtonState" geschrieben und können sie einfach nochmals aufrufen, bevor wir den Counter setzen.
function toggleLikeButtonState(button) {
const currentState = button.dataset.buttonState;
const likeCounter = document.querySelector("#data-like-counter");
// Alternative: document.getElementById("data-like-counter");
let currentCount = parseInt(likeCounter.textContent);
// bestehende Logik wiederverwenden
toggleButtonState(button, likePageText, unlikePageText);
if (currentState == "inactive") {
currentCount++;
} else {
currentCount--;
}
likeCounter.textContent = currentCount;
}
Refactoring
An der Lösung ist noch etwas unsauber, dass sich die Methode toggleLikeButtonState ums direkte setzten der Texte kĂŒmmert. Wir möchten auch hier die Texte als Parameter entgegen nehmen, auch wenn wir hier grundsĂ€tzlich "wissen" um welche Texte es sich handelt. Lagerst du die Verantwortung jedoch an den Aufrufer aus, dann ist die Methode "unabhĂ€ngig" und könnte einfacher umgezogen werden. Erweitere also die Methode genau gleich wie toggleButtonState um die zwei Parameter, ĂŒbergib dieses an die toggleButtonState Methode und ĂŒbergib die Werte wieder bei der Switch Methode.
case "like_article":
toggleLikeButtonState(button, likePageText, unlikePageText);
break;
function toggleLikeButtonState(button, activationText, inactivatingText) {
const currentState = button.dataset.buttonState;
const likeCounter = document.getElementById("data-like-counter");
let currentCount = parseInt(likeCounter.textContent);
toggleButtonState(button, activationText, inactivatingText);
Icon-Integration
Das Icon wird aktuell gelöscht, sobald du den Button drĂŒckst. Eigentlich möchten wir auch das Icon korrekt setzen. DafĂŒr erstellen wir zuerst einmal das nötige HTML, dass wir dann einsetzen können. Erstelle am Anfang des Scripts je eine Variable fĂŒr das "filledHeart" und das "brokenHeart".
SVG-Icons vorbereiten
const filledHeart = document.createElement("span");
const brokenHeart = document.createElement("span");
filledHeart.innerHTML = `<svg
fill="none" viewBox="0 0 16 16" width="16" height="16"
class="svg-icon">
<path fill="#fff" fill-rule="evenodd"
d="M13.971 3.029a3.53 3.53 0 0 0-4.983 0L8 4.018l-.988-.989a3.53 3.53 0 0 0-4.983 0 3.54 3.54 0 0 0 0 4.991L8 14l5.972-5.98a3.54 3.54 0 0 0 0-4.991"
clip-rule="evenodd"></path>
</svg>`;
brokenHeart.innerHTML = `<svg
fill="none" viewBox="0 0 16 16" width="16" height="16"
class="svg-icon">
<path fill="#000" fill-rule="evenodd"
d="M13.971 3.029a3.53 3.53 0 0 0-4.983 0L8 4.018l-.988-.989a3.53 3.53 0 0 0-4.983 0 3.54 3.54 0 0 0 0 4.991L8 14l5.972-5.98a3.54 3.54 0 0 0 0-4.991"
clip-rule="evenodd"></path>
<polyline points="6,4 8,8 7,10 9,12" stroke="#fff" stroke-width="1" fill="none"/>
</svg>`;
// Abstand zwischen Icon und Text
filledHeart.classList.add("mr-s");
brokenHeart.classList.add("mr-s");
ErklÀrungen
createElementerstellt ein HTML Element vom Typ, den du mitgibst- mit
innerHtmlkann HTML angefĂŒgt werden - der SVG Code selbst ist eher kommpliziert. Im Prinzip gibt es die Linien vor, die gezeichnet werden
Icons in Toggle-Funktion integrieren
if (currentState == "inactive") {
button.prepend(filledHeart);
currentCount++;
} else {
button.prepend(brokenHeart);
currentCount--;
}
đ Ergebnis
Alle Buttons sind jetzt voll funktionsfÀhig:
â
Like Button: Toggle mit Counter und Icon
â
Follow Author: Toggle mit Text-Ănderung
â
Follow Topic: Toggle mit Text-Ănderung
NĂ€chste Schritte
Im nĂ€chsten Kapitel verbinden wir die Buttons mit einem Backend fĂŒr persistente Datenspeicherung!