Quiz - Event-Handler dynamisch anbinden
Matthias Scharwies
- javascript
Servus!
ich dilettiere so vor mich hin und stoße bei der Umstrukturierung meiner unorganisierten Scripte auf immer mehr Fragen:
Z.20: Ist das quiz-Object so logisch?
var quiz = new Object();
quiz.question = 'Was ist die Hauptstadt von Deutschland?';
quiz.solution = 'Berlin';
quiz.options = ['Berlin', 'Hamburg', 'München', 'Hannover'];
z.52: Ich würde gerne den neu erzeugten Elementen eine Klasse oder einen Event-Handler geben. Wie geht das?
for (index = 0; index < quiz.options.length; index++) {
text = quiz.options[index];
newElement = addAChild('a', text);
//newElement.className = "foo";
}
Ich hatte dafür das a-Element gewählt, da ich dachte, dass man es dann auch durchtabben kann. Dafür benötigt es aber wohl noch ein href="#", oder?
Wie kann ich hier eine Klickfunktionalität erreichen? Wenn ich die Variable newElement noch einmal verwende, bricht die Schleife ab.
Auch der Versuch, die Funktion an den #quiz-Container anzuhängen und dann mit Event.target das geklickte Element zu identifizieren geht so nicht:
//...
var element = document.getElementById('quiz');
element.addEventListener('click',function(){clickHandler(event);});
}
function clickHandler(event) {
var target = event.target;
console.log(target);
}
Um den Event mit target zu identifizieren, benötige ich doch das Event, oder? Wie kann ich das übergeben?
Vielen Dank im Voraus!
Herzliche Grüße
Matthias Scharwies
Hallo Matthias
ich dilettiere so vor mich hin und stoße bei der Umstrukturierung meiner unorganisierten Scripte auf immer mehr Fragen:
Z.20: Ist das quiz-Object so logisch?
var quiz = new Object(); quiz.question = 'Was ist die Hauptstadt von Deutschland?'; quiz.solution = 'Berlin'; quiz.options = ['Berlin', 'Hamburg', 'München', 'Hannover'];
Ich kann hier keinen logischen Widerspruch erkennen, aber …
… warum rückst du hier die Anweisungen unterhalb der Variablendeklaration ein?
Wenn du eine Funktion mittels new
als Konstruktor aufrufst, ohne dabei Argumente zu übergeben, dann kannst du dir die runden Klammern nach deren Bezeichner sparen, denn der Aufruf ist bereits Teil der Semantik des Operators new
.
Andererseits wäre es wohl ohnehin besser, das Objekt in Literalschreibweise zu erstellen, so wie du es mit dem Array für die options ja auch gemacht hast, und nicht durch Aufruf des Konstruktors.
z.52: Ich würde gerne den neu erzeugten Elementen eine Klasse oder einen Event-Handler geben. Wie geht das?
for (index = 0; index < quiz.options.length; index++) { text = quiz.options[index]; newElement = addAChild('a', text); //newElement.className = "foo"; }
Ich hatte dafür das a-Element gewählt, da ich dachte, dass man es dann auch durchtabben kann. Dafür benötigt es aber wohl noch ein href="#", oder?
Wie kann ich hier eine Klickfunktionalität erreichen? Wenn ich die Variable newElement noch einmal verwende, bricht die Schleife ab.
Zunächst einmal bin ich mir ziemlich sicher, dass du hier keine Links willst, sondern Buttons vom Typ button
. Die sich übrigens auch prima durchtabben lassen.
Der Grund, warum dein Programm an dieser Stelle abschmiert, ist in der Funktion addAChild
zu suchen, deren Rückgabewert du der Variable newElement
zuweist. Da du für diese Funktion keinen Rückgabewert bestimmt hast, wird standardmäßig undefined
zurückgegeben, und der Versuch, diesem primitiven Wert eine Eigenschaft zuzuweisen, ergibt dann zwangsläufig einen Type Error.
Auch der Versuch, die Funktion an den #quiz-Container anzuhängen und dann mit Event.target das geklickte Element zu identifizieren geht so nicht:
//... var element = document.getElementById('quiz'); element.addEventListener('click',function(){clickHandler(event);}); } function clickHandler(event) { var target = event.target; console.log(target); }
Um den Event mit target zu identifizieren, benötige ich doch das Event, oder? Wie kann ich das übergeben?
Du hast als Event-Handler eine anonyme Funktion registriert, für die du keinen Parameter bestimmt hast. Innerhalb des Handlers rufst du dann eine Funktion mit dem Argument event
auf, aber wo soll das herkommen? Das ergibt natürlich einen Reference Error, da event
nicht definiert ist.
Du solltest also für die als Handler registrierte Funktion einen Parameter deklarieren:
element.addEventListener('click', function (event) {
clickHandler(event);
});
Wobei ein solches Konstrukt ohnehin recht wenig sinnhaft ist. Warum registrierst du clickHandler
nicht gleich als Event-Listener? – Oder verwendest die registrierte anonyme Funktion?
Viele Grüße,
Orlok
@@Orlok
Zunächst einmal bin ich mir ziemlich sicher, dass du hier keine Links willst, sondern Buttons vom Typ
button
.
Ich bin mir ziemlich sicher, dass du hier keine Buttons willst.
LLAP 🖖
Hallo Gunnar
Ich bin mir ziemlich sicher, dass du hier keine Buttons willst.
Oh man …
… wenn nichtmal das von Matthias bereits angegebene Stichwort options als Hinweis genügt. ;-)
Viele Grüße,
Orlok
Tach!
Z.20: Ist das quiz-Object so logisch?
Was für Bedenken hast du denn? Es erfüllt doch die Aufgabenstellung, oder nicht?
var quiz = new Object(); quiz.question = 'Was ist die Hauptstadt von Deutschland?'; quiz.solution = 'Berlin'; quiz.options = ['Berlin', 'Hamburg', 'München', 'Hannover'];
Man könnte vielleicht ändern, ein Objekt-Literal zu verwenden. Außerdem ist das Lösungswort redundant. Mit einem Verweis auf den Index des Options-Arrays könnte man sich das sparen.
z.52: Ich würde gerne den neu erzeugten Elementen eine Klasse oder einen Event-Handler geben. Wie geht das?
for (index = 0; index < quiz.options.length; index++) { text = quiz.options[index]; newElement = addAChild('a', text); //newElement.className = "foo"; }
Ich hatte dafür das a-Element gewählt, da ich dachte, dass man es dann auch durchtabben kann. Dafür benötigt es aber wohl noch ein href="#", oder?
Lässt sich tabindex nicht verwenden? Und sind das nicht eher Buttons als Links?
Wie kann ich hier eine Klickfunktionalität erreichen? Wenn ich die Variable newElement noch einmal verwende, bricht die Schleife ab.
Das macht sie nicht einfach so, sondern beschwert sich sicherlich über eine bestimmte Situation. Schau erstmal in der Konsole der Entwicklertools deines Browsers nach. Dann wirst du etwas feststellen und weitere Fragen bekommen.
//... var element = document.getElementById('quiz'); element.addEventListener('click',function(){clickHandler(event);}); } function clickHandler(event) { //...
Um den Event mit target zu identifizieren, benötige ich doch das Event, oder? Wie kann ich das übergeben?
Erstmal musst du es übernehmen. Das ist nicht einfach so auf magische Weise da, sondern wird dem Eventhandler übergeben. Das ist deine anonyme Funktion, und die nimmt nichts entgegen.
Die ist eigentlich auch überflüssig. Es reicht bei diesem einfachen Handler, dass du clickHandler direkt referenzierst. Diese Funktion nimmt ja auch ein Argument entgegen.
dedlfix.
Servus!
Vielen Dank ihr beiden!
Ist das quiz-Object so logisch? Was für Bedenken hast du denn? Es erfüllt doch die Aufgabenstellung, oder nicht?
Ich versuche grad bei einem Vokabeltrainer und einem Adventure Unmengen von Variablen in einen Zusammenhang zu setzen, und will da von Anfang an keine strukturellen Fehller machen.
Zunächst einmal bin ich mir ziemlich sicher, dass du hier keine Links willst, sondern Buttons vom Typ button. Die sich übrigens auch prima durchtabben lassen.
Danke, das wusste ich nicht, hatte vorher p und li.
Da du für diese Funktion keinen Rückgabewert bestimmt hast, wird standardmäßig undefined zurückgegeben,
bin grad Joggen gewesen, habe 'use strict'; eingesetzt und dann auch gemerkt, wo der Fehler lag. Das ist meine nächste Aufgabe und potentielle Fehlerquelle - Code in Helferfunktionen auszulagern, die den fertigen Code später einfacher machen, bis dahin aber erst mal getestet werden müssen.
clickHandler als Event-Listener?
danke, das werde ich mir anschauen.
Herzliche Grüße
Matthias Scharwies
@@Matthias Scharwies
Ich hatte dafür das a-Element gewählt, da ich dachte, dass man es dann auch durchtabben kann. Dafür benötigt es aber wohl noch ein href="#", oder?
Nei-en! href="#"
ist die Karte „Gehe zurück in die Badstraße“, d.h. zum Seitenanfang.
Wann immer du Nutzer nicht in die Badstraße schicken willst, ist href="#"
falsch und ein sicheres Zeichen dafür, dass das a
-Element falsch ist. Meist will man an der Stelle einen button
.
Du kannst übrigens beliebige Elemente mit tabindex="0"
duchtabbar machen. Und sie per role="button"
für AT zu Buttons machen und und und … und damit Steve Faulkners erste Regel zu ARIA missachten: Verwende nicht ARIA (wenn es passende HTML-Elemente / -Attribute gibt).
Wenn du einen Button willst, verwende button
.
Willst du aber hier nicht.
Du willst dem Nutzer eine Auswahl anbieten. Wenn du einen Auswahl willst, verwende select
. Wenn alle option
s sichtbar sein sollen, verwende das size
-Attribut.
Und die Quizfrage ist keine Überschrift, sondern die Beschriftung des Auswahlfeldes. Wenn du eine Beschriftung willst, verwende label
.
LLAP 🖖
Servus!
Du willst dem Nutzer eine Auswahl anbieten. Wenn du einen Auswahl willst, verwende
select
. Wenn alleoption
s sichtbar sein sollen, verwende dassize
-Attribut.
@@Gunnar Bittersmann,
Du hast im Prinzip recht. Aber wie kann man das select-Menü mit CSS stylen? Die appearance-Eigenschaft scheint da auch keine Lösung.
Wenn man ein Quiz, Vokabeltrainer oder Adventure für Jugendliche entwickeln möchte, sollte es nicht wie ein Anmeldungsformular für die mittlere-nichttechnische Laufbahn aussehen.
Wenn man dieses Quiz dann dank ARIA-Attributen, die man anstelle von Klassenselektoren auch zum Styling heranziehen kann, noch mit der Tastatur bedienen kann, umso besser.
Mich erinnert diese Diskussion an die um Buttons, als es hieß, dass Buttons aus Gründen der Übersichtlichkeit immer wie Betriebssystembuttons aussehen müssen, und du vernünftigerweise eine andere Meinung hattest.
Ich werde wohl <button role="option"> verwenden.
Herzliche Grüße
Matthias Scharwies
Hallo Matthias Scharwies,
Aber wie kann man das select-Menü mit CSS stylen? Die appearance-Eigenschaft scheint da auch keine Lösung.
Du willst ja nur die option-Elemente stylen.
select {
visibility: hidden;
}
option {
visibility: visible;
}
Wenn man ein Quiz, Vokabeltrainer oder Adventure für Jugendliche entwickeln möchte, sollte es nicht wie ein Anmeldungsformular für die mittlere-nichttechnische Laufbahn aussehen.
*g*
Mich erinnert diese Diskussion an die um Buttons, als es hieß, dass Buttons aus Gründen der Übersichtlichkeit immer wie Betriebssystembuttons aussehen müssen, und du vernünftigerweise eine andere Meinung hattest.
Da gibt es halt pro und contra.
Bis demnächst
Matthias
Hallo,
Du willst dem Nutzer eine Auswahl anbieten. Wenn du einen Auswahl willst, verwende
select
. Wenn alleoption
s sichtbar sein sollen, verwende dassize
-Attribut.
ich hätte für diesen Anwendungsfall, also die Auswahl von 1 aus n mit relativ kleinem n, eher eine Gruppe Radiobuttons empfohlen.
Und die Quizfrage ist keine Überschrift, sondern die Beschriftung des Auswahlfeldes. Wenn du eine Beschriftung willst, verwende
label
.
Dann wären die einzelnen Antwortoptionen die labels, und die Gruppenüberschrift ein legend des gruppierenden fieldset.
So long,
Martin
@@Der Martin
Du willst dem Nutzer eine Auswahl anbieten. Wenn du einen Auswahl willst, verwende
select
. Wenn alleoption
s sichtbar sein sollen, verwende dassize
-Attribut.ich hätte für diesen Anwendungsfall, also die Auswahl von 1 aus n mit relativ kleinem n, eher eine Gruppe Radiobuttons empfohlen.
Ja, auch gut.[1] [2] Wie beim Tic-Tac-Toe.
Dann wären die einzelnen Antwortoptionen die labels, und die Gruppenüberschrift ein legend des gruppierenden fieldset.
So isses.
LLAP 🖖
Lieber Matthias,
ich hab da mal was gebastelt... jsFiddle
Komisch, dass bei Tastatureingaben immer wieder ein Auto-Click-Event hinterhergefeuert wird. Konnte das auch in Chromium so beobachten. Wie kann man dieses Auto-Click wieder weg kriegen? Bei allem ARIA-Gesinge, das ist ja wohl wirklich ein Schuss ins eigene Knie!
Liebe Grüße,
Felix Riesterer.
Hallo,
Komisch, dass bei Tastatureingaben immer wieder ein Auto-Click-Event hinterhergefeuert wird. Konnte das auch in Chromium so beobachten. Wie kann man dieses Auto-Click wieder weg kriegen?
warum stört dich das? Ist doch eine sinnvolle Sache - so kommen auch Webentwickler, die nicht an Tastatureingaben denken, sondern nur an Klick-Events, noch zu einer halbwegs funktionierenden Webapplikation.
Bei allem ARIA-Gesinge, das ist ja wohl wirklich ein Schuss ins eigene Knie!
Inwiefern? Wenn du auf beides (Tastatur und Klick) reagierst, wird das entsprechende Element halt zweimal quasi-gleichzeitig ausgewählt. Na und?
So long,
Martin
Lieber Martin,
Inwiefern? Wenn du auf beides (Tastatur und Klick) reagierst, wird das entsprechende Element halt zweimal quasi-gleichzeitig ausgewählt. Na und?
das führt aber zu unabsichtlicher Fehlbedienung! Hättest Du das Beispiel ausprobiert (erst mit TAB-Taste die Radio-Buttons erreichen, dann mit den Pfeiltasten auswählen - anschließend per Enter-Taste bestätigen), dann wäre Dir aufgefallen, dass bereits das Auswählen der gewünschten Option als "Click" und damit als definitive Entscheidung gewertet wird - obwohl das nur auch einen echten Click oder die Enter-Taste hin der Fall sein sollte.
Liebe Grüße,
Felix Riesterer.
Lieber Felix,
das führt aber zu unabsichtlicher Fehlbedienung!
deswegen nimmst Du lieber mousedown
anstatt click
. Damit die Radio-Buttons ihren Zustand ändern können, bevor Dein Mausevent sie prüft, muss man eine Verzögerung (setTimeout) setzen. Sonst braucht es seltsamerweise einen doppelten Klick.
Liebe Grüße,
Felix Riesterer.
Hallo,
Inwiefern? Wenn du auf beides (Tastatur und Klick) reagierst, wird das entsprechende Element halt zweimal quasi-gleichzeitig ausgewählt. Na und?
das führt aber zu unabsichtlicher Fehlbedienung! Hättest Du das Beispiel ausprobiert ...
das habe ich deshalb nicht ausprobiert, weil auf jsfiddle.net ohne Javascript überhaupt nichts sichtbar und bedienbar ist.
(erst mit TAB-Taste die Radio-Buttons erreichen, dann mit den Pfeiltasten auswählen - anschließend per Enter-Taste bestätigen)
Moment. Mit der Tab-Taste die Radiobuttons als Gruppe auswählen, okay. Dann mit den Cursortasten eine der Optionen auswählen, okay. Das wird gleichzeitig als Pseudo-Klick interpretiert, denn das ist bereits die verbindliche Auswahl.
Aber das Drücken der Enter-Taste gehört nicht dazu. Das bewirkt bei den Radiobuttons nichts (sollte jedenfalls nicht), sondern löst nur das Absenden des umschließenden Formulars aus, wenn es eins gibt.
dann wäre Dir aufgefallen, dass bereits das Auswählen der gewünschten Option als "Click" und damit als definitive Entscheidung gewertet wird
Also so, wie man es erwarten sollte.
obwohl das nur auch einen echten Click oder die Enter-Taste hin der Fall sein sollte.
Ich würde sagen, da hast du eine falsche Erwartungshaltung. Meines Wissens bewirkt die Enter-Taste auf die Radiobuttons bezogen nichts.
So long,
Martin
Lieber Martin,
Ich würde sagen, da hast du eine falsche Erwartungshaltung. Meines Wissens bewirkt die Enter-Taste auf die Radiobuttons bezogen nichts.
Du hast natürlich (wieder einmal) Recht. Allerdings versuche ich hier das ARIA-bewusste Umsetzen eines ansonsten simplen Quizzes, welches primär simpel mit der Maus bedient werden soll. Nur wenn jemand auf Tastatureingaben angewiesen sein sollte, braucht es ein im Grunde anderes User Interface. Der Mausakrobat klickt auf die gewünschte Antwort und das Quiz wertet sie sofort aus. Der Tastaturkämpfer fokussiert erst einmal die Gruppe der Radio-Buttons, hangelt sich dann zum gewünschten durch und bestätigt seine Auswahl.
Wie vereint man diese beiden Bedienkonzepte? Der Tastaturkämpfer ist einen Submit-Button gewohnt, der seine Auswahl bestätigt, der Mausakrobat gerade eben nicht. Letzterer will den Button erst gar nicht sehen! Also wie setzt man soetwas ansonsten um, wenn nicht wie in meinem Beispiel (und ja, dafür benötigt man offensichtlich JavaScript)?
Liebe Grüße,
Felix Riesterer.
Hallo Felix,
Ich würde sagen, da hast du eine falsche Erwartungshaltung. Meines Wissens bewirkt die Enter-Taste auf die Radiobuttons bezogen nichts.
Du hast natürlich (wieder einmal) Recht.
na, nun übertreib mal nicht. ;-)
Allerdings versuche ich hier das ARIA-bewusste Umsetzen eines ansonsten simplen Quizzes, welches primär simpel mit der Maus bedient werden soll. Nur wenn jemand auf Tastatureingaben angewiesen sein sollte, braucht es ein im Grunde anderes User Interface. Der Mausakrobat klickt auf die gewünschte Antwort und das Quiz wertet sie sofort aus.
Das wäre aber ein Verhalten, das ich normalerweise nicht erwarten würde - jedenfalls nicht bei einem Element, das mich aus einer Menge von Optionen auswählen lässt. Da ist der Normalfall eher, dass ich mich noch beliebig oft umentscheiden kann, bevor die Auswahl endgültig wirksam wird, sprich: die Eingabe bestätigt wird. Typischerweise durch einen Submit-Button.
Der Tastaturkämpfer fokussiert erst einmal die Gruppe der Radio-Buttons, hangelt sich dann zum gewünschten durch und bestätigt seine Auswahl.
Genau. Wobei das Bestätigen auch erst erfolgt, nachdem alle Auswahlmöglichkeiten getroffen sind. Wenn also beispielsweise vier Gruppen von Radiobuttons da sind, würde dieser letzte Schritt alle vier miteinander bestätigen. Einzeln wäre sehr ungewöhnlich.
Wie vereint man diese beiden Bedienkonzepte?
Keine Ahnung. Für mich sind sie nicht verschieden.
Der Tastaturkämpfer ist einen Submit-Button gewohnt, der seine Auswahl bestätigt, der Mausakrobat gerade eben nicht.
Doch, an den Klick auf einen Submit-Button ist der in der Regel auch gewöhnt. Wobei manche UIs diesen Schritt vereinfachen, indem sie einen Doppelklick auf ein Formularelement, das normalerweise nur auf Einzelklicks reagiert, als Abschließen der Eingabe werten. Beispiel: Datei-Auswahldialoge; Einstell-Dialoge in Word.
Letzterer will den Button erst gar nicht sehen!
Doch, bitte. Unbedingt.
So long,
Martin
@@Felix Riesterer
Allerdings versuche ich hier das ARIA-bewusste Umsetzen eines ansonsten simplen Quizzes
Ich bin positiv überrascht.
Mit „ARIA-bewusst“ meinst du „barrierefrei“? Ob man dazu ARIA braucht oder ob HTML-„Hausmittel“ genügen, steht auf’m anderen Blatt.
welches primär simpel mit der Maus bedient werden soll. Nur wenn jemand auf Tastatureingaben angewiesen sein sollte
“Everybody is a keyboard user when eating lunch with their mouse hand.” —Adrian Roselli (Quelle, siehe auch Nachfrage vom Schepp ;-))
braucht es ein im Grunde anderes User Interface. Der Mausakrobat klickt auf die gewünschte Antwort und das Quiz wertet sie sofort aus. Der Tastaturkämpfer fokussiert erst einmal die Gruppe der Radio-Buttons, hangelt sich dann zum gewünschten durch und bestätigt seine Auswahl.
Wie vereint man diese beiden Bedienkonzepte? Der Tastaturkämpfer ist einen Submit-Button gewohnt, der seine Auswahl bestätigt, der Mausakrobat gerade eben nicht. Letzterer will den Button erst gar nicht sehen!
Submit-Button, der bei aktiviertem JavaScript visuell versteckt wird, aber in der Tab-Reihenfolge bleibt. Bei :focus
wird er angezeigt.
Nur so’ne Idee, ohne tiefer drüber nachgedacht zu haben. Könnte auch ’ne Schnapsidee sein.
LLAP 🖖
Lieber Gunnar,
Ich bin positiv überrascht.
ach komm jetzt! Prinzipiell war ich nie Überlegungen zur Barrierefreiheit abgeneigt. Meine Ablehnung war nur im Kontext der inhaltlichen Menge und technischen Komplexität eines Anfängertutorials. Wenn man in fortgeschrittener Manier soetwas angeht, dann darf es ruhig komplexer und dafür barrierefrei sein.
Mit „ARIA-bewusst“ meinst du „barrierefrei“? Ob man dazu ARIA braucht oder ob HTML-„Hausmittel“ genügen, steht auf’m anderen Blatt.
Also: Hier ist ein Versuch, der es recht machen will. Bitte ausprobieren und hinsichtlich Zugänglichkeit kritisieren (und nein, ohne JavaScript ist das gesamte Quiz nicht zugänglich - by design!).
“Everybody is a keyboard user when eating lunch with their mouse hand.” —Adrian Roselli (Quelle, siehe auch Nachfrage vom Schepp ;-))
Keyboard only funktioniert. Die jeweils erste Auswahlmöglichkeit wird automatisch fokussiert und vorausgewählt. Damit sollte eine reine Tastaturbedienung auf die Pfeiltasten und die Entertaste beschränkt funktionieren. Die Tab-Taste zum Erreichen der ursprünglichen Radio-Buttons (man sieht sie ja jetzt nicht mehr) ist dadurch nicht mehr notwenig.
Submit-Button, der bei aktiviertem JavaScript visuell versteckt wird, aber in der Tab-Reihenfolge bleibt. Bei
:focus
wird er angezeigt.
Er wird überhaupt nicht angezeigt. Das Formular (das habe ich jetzt eingebaut) kann mit der Enter-Taste abgeschickt werden. Dabei wird das submit-Event abgefangen.
Liebe Grüße,
Felix Riesterer.
Servus!
Lieber Matthias,
ich hab da mal was gebastelt... jsFiddle
Danke, kann ich mir aber erst morgen näher anschauen!
Herzliche Grüße
Matthias Scharwies