Der Martin: Toggle Button verweigert den Dienst!

Beitrag lesen

Hi,

ok ich scheitere schon wieder an Grundsätzlichem :(

ja, dein Ansatz ist unter mehreren Gesichtspunkten ungünstig bzw. sogar falsch.

Was ich erreichen will ist eigentlich genauso simpel wie es trivial ist - ein Toggle Button als Bestandteil eines Javascript Quiz.

Dabei wird bei jedem Klick auf einen Link eine Funktion ausgelöst, die die Variable "eins" von false auf true setzt und den Link rot färbt. Wurde der Link allerdings bereits angeklickt, so wird die Variable "eins" wieder auf false zurückgesetzt und der Link wird grün;

Halten wir hier mal inne. Du willst beim Klicken den Zustand eines Elements ändern, das über eine ID angesprochen wird. Also brauchst du die ID als String. Gleichzeitig willst du den Zustand aber noch einmal in einer boolschen Variable halten, die dazu auch noch global ist. Warum doppelt? Frag doch an der entscheidenden Stelle direkt den Element-Status ab.

Ich würde das Umschalten des Status realisieren, indem ich dem Element eine Klasse (z.B. "active") geben bzw. sie wieder wegnehme. Praktischerweise gibt's dafür schon was fertiges. Vom Vorhandensein dieser Klasse kann man dann auch gleich die Darstellung abhängig machen und diese Angaben ins Stylesheet verschieben, wo sie hingehören. Damit reduziert sich die Funktion auf eine einzige Anweisung, wenn man die Fehlerbehandlung außer Acht lässt. Das wollen wir aber nicht; das Script soll auch dann nicht auf die Schnauze fallen, wenn es gar kein Element mit der angegebenen ID gibt:

function toggleStatus(eID)
 { var eRef = document.getElementById(eID);       // Element anhand der ID im DOM suchen

   if (eRef)                                      // Element gefunden?
    { eRef.classList.toggle("active");            // Klasse hinzufügen bzw. wegnehmen
      return (eRef.classList.contains("active");  // neuen Status zurückliefern
    }
   else                                           // im Fehlerfall (Element existiert nicht)
      return (null);                              // null als Fehler-Kennzeichen zurückgeben
 }

Es gehört irgendwie zum guten Ton, dass eine Funktion auch ein Ergebnis zurückliefert; ich habe in diesem Fall den neuen Status nach dem Toggeln gewählt (true oder false), bzw. null im Fehlerfall.

Kommen wir nun zum Aufruf der Funktion. Du hast dafür ein a-Element gewählt, und das ist eigentlich unpassend. Ein Link dient zum Aufruf einer neuen HTML-Seite, du willst aber eine Funktion innerhalb der Seite auslösen. Dafür ist das button-Element da. Also etwa so:

<button id="eins" onclick="toggleStatus('eins');">Aktiv/Inaktiv</button>

Mit CSS kann man sich den Button dann schönformatieren, wie man gerne möchte. Dasselbe für den Auswerten-Button.

Jetzt fehlt noch deine Auswertung; auch hier fragen wir einfach die classList des ausgewählten Elements ab, ob die Klasse "active" derzeit gesetzt ist:

function Auswertung(eID)
 { var eRef = document.getElementById(eID);       // Element anhand der ID im DOM suchen

   if (eRef)                                      // Element gefunden?
    { if (eRef.classList.contains("active")       // Klasse ist vorhanden
       { // Anweisungen für den OK-Fall
       }
      else
       { // Anweisungen für den Fehler-Fall
       }
    }
 }

Nichts davon funktioniert leider. . . warum nicht?

Sehen wir uns die entscheidenden Fehler bei dir an.

<ul>
	<li><a href='javascript:klick(eins);' id="eins">Ich bin ein Link.</a></li>
</ul>

Du übergibst den aktuellen Wert von eins, also true oder false. Innerhalb der Funktion versucht dann document.getElementById(), ein Element mit der ID true bzw. false zu finden, das geht in die Hose.

function klick(n) {
	if (n == false) {
		n = true;
		document.getElementById(n).style.color = "red"; 
	} else {
		n = false;
		document.getElementById(n).style.color = "green"; 
	}
}

Vom falschen Parametertyp mal abgesehen mixt du hier lustig Variablennamen, Variablenwerte und ID-Werte. Was du da machst, ist in Programmiersprachen wie C mit Zeigern durchaus möglich: Einer Funktion nicht den Wert einer Variablen zu übergeben, sondern eine sogenannte Referenz auf eine Variable außerhalb der Funktion. Mit JS ist das AFAIK nicht möglich.

Was noch dazukommt: In deinem Code ist n eine lokale Variable in der Funktion. Ihr Wert wird aber nie auf die globale Variable eins zurückgeschrieben, deren Wert du übergeben hast.

So long,
 Martin

PS: Mit dem Vorschlag von pl, als zustandsspeicherndes Element ein checkbox-Element (einschließlich des zugehörigen label-Elements, versteht sich) zu verwenden, wird es noch wesentlich einfacher und eleganter. Das Umschalten erledigt der Browser ganz allein, und die Statusabfrage beschränkt sich auf das Abfragen der checked-Eigenschaft. Auch das Styling kann man dann von der Pseudoklasse :checked abhängig machen.

--
Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
- Douglas Adams, The Hitchhiker's Guide To The Galaxy