Quiz mit Javascript erstellt - bitte um Code-Beurteilung

  • Zitat

    mit der Berechnung im TimeOut funktioniert es, allerdings auf meinem Rechner erst ab 50 ms. 10 ms sind ihm zu wenig, dann ist die Berechnung falsch und der Wert noch zu gering. Bei diesem Vorgehen ist man also darauf angewiesen, dass der Server nicht allzu langsam antwortet.

    Das verstehe ich jetzt nicht ganz, warum man auf die Antwort vom Server warten muss. Die Berechnung findet ja innerhalb des then-Zweiges für die Anfrage statt, d. h. dort sollte die Antwort vollständig vorliegen. Es sei denn, ich habe mich mit den Klammern irgend wie verguckt.


    Aber ich erwarte, dass sich das Ganze auch mit CSS lösen lässt, siehe meine vorigen Postings. Dann würde sich das Problem erübrigen.

  • Ich habe das TimeOut mit 10 ms in mein Script eingebaut und bekam falsche Werte. Dann habe ich die Zeit langsam nach oben angepasst, und erst bei 50 ms war die Berechnung richtig. Daraus habe ich geschlossen, dass die Verarbeitungszeit ein Kriterium ist und dass mein MAMP halt ein wenig träge reagiert.


    Die Lösung mit CSS Grid finde ich beeindruckend, danke Dir herzlich! Überhaupt bin ich von CSS Grid sehr begeistert und habe aber bisher nur einen Bruchteil der Möglichkeiten nutzen können. Für mein Quiz werde ich auf alle Fälle Deine Idee verwenden.


    Eine schöne Woche wünsche ich!

  • Normalerweise ärgert man sich ja, wenn etwas nicht funktioniert. Ich ärgere mich gerade, weil etwas funktioniert und ich nicht weiß, wieso.



    Der EventListener tut hier das, was er soll … obwohl die Elemente start und prologue überhaupt nicht mit document.getElementById() definiert worden sind.


    Ist mir etwas entgangen? Reicht es aus, dass die Elemente im HTML-Code eindeutig bezeichnet sind? Seltsamerweise habe ich noch nie etwas davon gehört oder gelesen, dass man document.getElementById() weglassen könnte, im Gegenteil: Mir wurde es so beigebracht, und bisher hat nie jemand daran Anstoß genommen …

  • Das ist eine Eigenart von Javascript in Verbindung mit HTML: Gibt man einem Element eine ID, so ist es automatisch auch als globale Variable mit der ID als Name definiert. Etwas wovon man besser keinen Gebrauch machen sollte. Die Probleme gehen los, wenn man z. B. Minuszeichen in der ID hat: Dann funktioniert das mit dem Variablennamen nicht aber man findet z. B. solch ein div <div id="test-global-var"></div> als window['test-global-var'] wieder.

  • Danke Dir für die Info! Also ging meine Vermutung schon in die richtige Richtung. Seltsam, dass das bisher in keinem mir bekannten Tutorial und auch nicht in meinem Videokurs erwähnt wurde. Und ja, ich bleibe bei der „traditionellen“ Vorgehensweise … :)

  • Ich habe nun eine erste Version meines datenbankgestützten Musik-Quiz' erstellt: http://music-quiz.bplaced.net/mq01/


    Das ist noch nicht das, wo ich hin will, es sind auch noch Bugs drin, die ich beseitigen muss. Aber eine Sache ärgert mich sehr, und ich finde dafür keine Lösung: Man kann schnell hintereinander eine falsche und die richtige Antwort (oder andersrum) auswählen und bekommt dann beide Overlays zu sehen, das rote und das grüne.


    Ich hatte once: true für den EventListener ergoogelt, aber das zeigt keine Wirkung. Außerdem hätte ich ohnehin nicht gewusst, wie ich es für die zweite Frage wieder loswerde.


    Mir ist eine Lösung eingefallen, die sehr unsauber wäre: Ich könnte mit dem Klick auf einen Antwortbutton ein leeres Div mit opacity: 0 über die Fragen legen, dann wäre kein weiterer Klick mehr möglich. Aber das wäre selbst mir zu laienhaft … ;)


    Ich wäre also dankbar für einen Hinweis, wie ich während des Timeouts vom ersten Klick auf eine Antwort bis zum Erscheinen des Overlays weitere Klicks auf die Antwortbuttons verhindern kann.

  • Ohne in den Code eingestiegen zu sein fallen mir mehrere Möglichkeiten ein:

    1. Eine globale Variable beim Klick auf eine Antwort setzen und im Eventhandler abfragen. Ist sie gesetzt, dann den Klick ignorieren.
    2. Eine Klasse bei den Buttons setzen und im Eventhandler abfragen. Ist sie gesetzt, dann den Klick ignorieren.
    3. Das CSS pointer-events: none; für die Buttons setzen. Dann werden Mausklicks ignoriert.

    Alles lässt sich problemlos rückgängig machen, wenn wieder eine Frage präsentiert wird.

  • Schöne Feiertage allerseits!


    Mein Quiz ist eigentlich fertig, aber nur eigentlich, denn ich habe einen Bug entdeckt, dessen Herkunft ich nicht wirklich verstehe:


    http://music-quiz.bplaced.net/test03/

    http://music-quiz.bplaced.net/test03/musicQuiz.js


    Alles, was innerhalb von function makeQuestion(countofquestions) (Zeile 244) abläuft, wird mit countofquestions hochgezählt. Also, bei der ersten Frage läuft es einmal ab, bei der zweiten zweimal, bei der dritten dreimal etc. Man kann das mit dem Debugger feststellen oder einfach im Network-Tab schauen: Mit jedem Aufruf von getQuestions.php wird checkAnswer.php einmal mehr aufgerufen.


    Wie kann ich die Stelle finden, an der der Bug sitzt, und wie kann ich das Untier eliminieren?

  • Danke, ich wünsche ebenfalls einen angenehmen Rest von den Weihnachstsfeiertagen!

    Das liegt daran, dass Du jedes Mal, wenn Du eine neue Frage holst, die Eventlistener für Klick auf den Button neu registrierst. Deshalb werden es mit jeder Frage mehr. Das HTML der Buttons bleibt ja unverändert und die alten Eventlistener bleiben bestehen.

    Etwas anderes wäre es, wenn Du das innerHTML des ganzen Containers div.question austauschen würdest. Dann würden die Buttons neu erzeugt und die alten Eventlistener gingen verloren und müssten neu registriert werden.

  • Herzlichen Dank, das ging ja wieder fix! :)


    Meinst Du, ich sollte die Buttons mit JavaScript, also mit createElement und appendChild erzeugen? Derzeit stehen die Buttons ja statisch im HTML-Code.

  • Zitat

    Muss der Code Eventlistener an eine andere Stelle?

    Ja genau, im Moment steht der Code mit dem addEventListener ja innerhalb des then-Zweiges beim fetch für das Holen einer neuen Frage und wird dort immer wieder ausgeführt. Du musst ihn dort heraus nehmen und z. B. am Ende des Skriptes platzieren wo Du die anderen Eventlistener registrierst.

  • Der zweite Feiertag, und ich bin gerade völlig frustriert. Nein, nicht über die minus 12 Grad draußen, sondern darüber, dass ich obige Aufgabe nicht lösen kann. Ich gerate dabei genau an den Punkt, der meine größte Schwachstelle beim Programmieren ist: Ich kann mir die Abläufe nicht bildlich vorstellen, und das ärgert mich gewaltig.


    Der Eventlistener beinhaltet sozusagen das Herz dieses Spiels. Wenn ich irgendwas verändere – und ich habe gestern Abend und heute Morgen etliches versucht –, werden die verschiedensten Fehlermeldungen ausgespuckt.


    Jetzt habe ich zwei Anliegen: Erstens wäre ich natürlich dankbar für die Lösung dieses Rätsels. Und zweitens: Wie kann ich meine Vorstellungskraft für die Abläufe trainieren? Immer, wenn es um Verschachtelungen geht, steigt mein Gehirn aus. :(


    Ich wünsche einen schönen zweiten Feiertag mit gut funktionierenden Heizungen, wärmestrahlenden Öfen oder knisternden Kaminen!

  • Danke für die guten Wünsche, ich wünsche ebenfalls einen angenehmen 2. Feiertag!


    Ich habe mir das jetzt etwas genauer angesehen und bemerkt, dass es mit einem trivialen Verschieben des Registrierens nicht getan ist, denn innerhalb der Listener wird auf die Antwort vom Server zugegriffen und die steht nach dem Verschieben nicht zu Verfügung. Man kann das jedoch relativ leicht lösen, indem man den Text der Antwort aus dem innerHTML des betr. Buttons liest. Hier das geänderte Javascript, ich habe die geänderten Stellen mit !!! markiert:

    https://pastebin.com/FXekS8LQ

    Ich hatte vor, es zu testen, habe dann aber bemerkt, dass mir dafür die Datenbank und das PHP fehlt. Daher ungetestet.


    Zitat

    Und zweitens: Wie kann ich meine Vorstellungskraft für die Abläufe trainieren? Immer, wenn es um Verschachtelungen geht, steigt mein Gehirn aus.

    Um einen Überblick über die Verschachtelungen im Code zu bekommen, sind das A und O die sinnvollen Einrückungen des Codes aber die hast Du ja schon, wie ich sehe.

    Etwas anderes sind die zeitlichen Abläufe. Man muss ein Gefühl dafür bekommen, wann ein Codeabschnitt ausgeführt wird und welche Variablen dabei zur Verfügung stehen. Die kritischen Dinge sind hier:

    • Das Holen von Daten vom Server mit fetch. Dabei muss man sich im klaren darüber sein, dass das asynchron abläuft und die Antwort nur im then-Zweig zur Verfügung steht.
    • Die Eventlistener. Hier muss man sich im klaren darüber sein, dass der Code darin erst ausgeführt wird, wenn, in unserem Fall, auf einen Button geklickt wird. Und ein Fallstrick in der Form, dass immer mehr und mehr Listener registriert werden.

    Hier braucht es u. U. Übung und Erfahrung um die Abläufe schneller zu verstehen.

  • So, ich habe mir mittlerweile alles angeschaut – ganz herzlichen Dank für Deine Mühe, Sempervivum !


    Leider gibt es gibt beim Klick auf einen Button keinerlei Reaktion. Nicht mal eine Fehlermeldung in der Konsole, es passiert einfach nichts. Deswegen habe ich alles inklusive Deines Scripts online gestellt:


    http://music-quiz.bplaced.net/test04/

    http://music-quiz.bplaced.net/test04/sempervivum.js


    Ich habe Dir – Sempervivum – auch einen Datenbankdump und die PHP-Dateien an dieses Posting angehängt, falls Du lokal testen möchtest. Klar, dass ein Stochern im Dunkel keine wirklichen Aufschlüsse bringt. Ich staune schon immer, wie Du mit einem Blick auf ein Script weißt, was es tun wird. ;)


    Die Zugangsdaten in den PHP-Dateien sind absolut unverfänglich, also kein Problem, falls sich das noch irgendwer herunterlädt.


    Zum zweiten Teil des Postings: An Übung und Erfahrung fehlt es mir völlig, wie hier ja unschwer zu erkennen ist. Trotzdem merke ich, dass ich doch schon einiges gelernt habe, wozu natürlich Deine Unterstützung hier massiv beigetragen hat.


    Auf den Bug mit dem vielfachen Eventlistener bin ich übrigens gekommen, weil ich eine weitere Version dieses Quiz basteln will, und zwar eine, in der man erst am Ende angezeigt bekommt, welche Fragen man richtig und welche falsch beantwortet hat. Dazu habe ich bereits eine PHP-Datei, welche mir die korrekten Antwortnummern liefert. Mit JavaScript wollte ich dann die Nummern der gegebenen Antworten (man kann dann nur einmal pro Frage klicken) in ein Array speichern und aus diesen beiden Arrays einen Vergleich erstellen. Und beim Speichern des Arrays ist mir aufgefallen, dass die Zahlen immer mehr und mehr und mehr wurden … ;)


    Einen geruhsamen Feiersonntagsabend wünsche ich!

  • Verflixt, ich hatte vergessen, auf einen Punkt hinzuweisen: Damit man die Buttons leicht ermitteln kann, muss man dem Container die Klasse "answers" geben:

    Code
    <div class="backgroundLight answers">

    Die Nodelist mit den Buttons wird ja mit diesem Selektor ermittelt:

    Code
    const answerBtns = document.querySelectorAll('div.answers button');

    Fehlt die Klasse "answers" bleibt die Nodelist leer und nichts passiert wenn man versucht, die Eventlistener zu registrieren.


    Hast Du dich schon mit dem Debugger für Javascript vertraut gemacht? Dieser ist sehr hilfreich, wenn man solche Fehler finden will. Man muss nicht jedes Mal ein console.log einfügen, um eine Variable zu überprüfen etc.

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!