Quiz mit Javascript erstellt - bitte um Code-Beurteilung

  • Das habe ich jetzt verstanden, d. h. ich glaube es zu verstehen:



    Ist das so halbwegs richtig ausgedrückt?


    Und danke natürlich! :)

  • Der Code an sich scheint mir richtig zu sein, nur dieser Kommentar:

    Zitat

    // Hier wird eine Funktion definiert, die einen Wert zurückgeben soll:

    ist IMO missverständlich: Unter "einen Wert zurückgeben" versteht man i. allg. dass die Funktion einen Rückgabewert mit der return-Anweisung zurück gibt. Das ist jedoch hier nicht der Fall sondern die Funktion, die als callback übergeben wurde, wird aufgerufen und der Wert als Parameter übergeben.

  • Sprachlich ist JavaScript eine echte Herausforderung für mich – gemeint ist damit, dass ich das, was ich als Code sehe, oft nur schwer in Worte fassen kann.


    Ich schrieb es an anderer Stelle schon mal: Wenn ich den Code, den ich lese, nicht mit eigenen Worten beschreiben kann, dann habe ich ihn nicht verstanden, und wenn ich ihn nicht verstanden habe, gibt es Lernbedarf.


    Mir ist es soeben gelungen, den Code für mein Musik-Quiz anzupassen, und er funktioniert! Danke noch einmal, Sempervivum – für Deine Geduld und Deine Unterstützung!


    Ich werde jetzt mal schauen, ob ich bei YouTube ein Video zum Thema finde, denn ein wenig verfestigen sollte ich das heute Gelernte durchaus, und da wäre eine Kombination aus Bild und Ton sicher das hilfreichste.

  • Ich glaube, ich habe jetzt das Grundprinzip des Callbacks verstanden. Aber es bleiben Fragen offen ...



    Bei diesem Code liefert mir die Funktion counter beide Werte, den von i und den von j. Das liegt vermutlich daran, dass beide mit dem Parameter callback übergeben werden. Ob ich in der Funktion getCounter von der Konsole i oder j ausgeben lasse, ist auch egal.


    Also habe ich so etwas versucht:



    Das liefert die Fehlermeldung "Uncaught TypeError: newCallback is not a function at counter ...".


    Wie müsste ich denn vorgehen, wenn die die Werte aus counter getrennt oder wahlweise übergeben möchte?

  • Die Funktion counter hat 2 Parameter; beide müssen Funktionen sein mit jeweils einem Parameter. getCounter definierst Du jedoch mit 2 Parametern Du kannst ohne weiteres counter mit zwei Mal der selben Funktion aufrufen:

    Code
    1. function getCounter(idx) {
    2. console.log(idx);
    3. }
    4. counter(getCounter, getCounter)
  • Ich schlage mich schon einen halben Tag mit einem Problem herum, für das ich keine Lösung finde. Wenn Ihr Euch bitte einmal diese Seite anschauen würdet:


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


    Der flache rote Bereich ganz oben dürfte eigentlich gar nicht zu sehen sein, denn dieses Div mit der ID redOverlay hat ein negatives Margin, das der Höhe des Divs mit der ID playpart entspricht. Die Höhe bestimme ich mit offsetHeight im externen JavaScript.


    Theoretisch eine simple Sache, die ich auch schon mehrfach angewendet habe, aber hier bleibt eine Differenz von 30 Pixeln zwischen der von Javascript ausgelesenen Höhe und der optischen bzw. mittels DevTools ermittelten Höhe von playpart.


    Ich habe zum Debuggen nach und nach alles CSS und alles JavaScript entfernt, bis ich als offensichtlichen Verursacher etwas feststellte, das ich niemals erwartet hätte, nämlich:


    Code
    1. body {
    2. font-family: "Noto Sans JP", sans-serif;
    3. ...
    4. }


    Entfernt man "Noto Sans JP",, schreibt also nur font-family: sans-serif;, verschwinden auch die 30 Pixel Differenz. Und darauf kann ich mir keinen Reim machen. Gar keinen.


    Wieso sollte eine Schriftart diesen Fehler auslösen? Ich habe andere Schriftfamilien eingebunden – dasselbe Ergebnis, höchstens mit einigen Pixeln unterschiedlicher Differenz.


    Hat jemand von Euch eine Erklärung dafür? Oder habe ich einen Bug eingebaut, der so groß ist, dass ich ihn nicht sehe?

  • Mir scheint, die Erklärung ist folgende: Du berechnest die Höhe des roten Divs ja mit Javascript und das steht direkt vor dem schließenden </body> und wird sofort ausgeführt, nachdem das HTML eingelesen wurde. Das ist normaler Weise vollkommen OK, nur hier ist es so, dass Du diese Schriftart "Noto Sans JP" von extern lädst. Das dauert einen kurzen Moment und offenbar wird das Javascript ausgeführt, bevor die Schrift vollständig geladen ist und daher wird die Höhe dieser Schrift nicht berücksichtigt. Dies dürfte sich beheben lassen, indem Du das Javascript erst im load-Event ausführst, dann sollte sicher gestellt sein, dass alle externen Dateien vollständig geladen sind.

  • Deine Vermutung ist absolut richtig, und wie immer danke ich Dir für Deine schnelle Reaktion! :)


    Ich hab’ unter o. g. Link mal zwei Textbeispiele eingefügt. Man sieht deutlich, dass der Designer des Google-Fonts den Durchschuss ganz anders berechnet als es beim serifenlosen Systemfont (i. d. R. Arial oder Helvetica) der Fall ist.

  • Gerade glaubte ich, ein Problem beseitigt zu haben, da tritt es an anderer Stelle ganz verstärkt wieder auf:



    Das ist (gekürzt) das JavaScript für mein Musik-Quiz, jetzt mit window.addEventListener('load', (event), was beim Problem mit dem Google-Font die Lösung brachte. Hier funktioniert das aber nicht, denn das Laden der Inhalte aus der Datenbank bringt die Berechnung der Höhe für HTML-Elemente völlig durcheinander.


    Die Höhe, die JavaScript für das HTML-Element mit der Quiz-Frage und den Antworten berechnet, ist die Höhe ohne Inhalte. Das Laden per PHP aus der Datenbank erfolgt also erst, wenn das JavaScript vollkommen ausgeführt wurde. Die Inhalte erzeugen dann eine wesentlich größere Höhe.


    Wie gehe ich denn nun vor? Habe ich den EventListener falsch eingesetzt?


    Leider kann ich kein Beispiel online stellen, da ich die DB nur lokal zur Verfügung habe.


    ---


    Nachtrag: Habe gerade noch mal über das Ganze nachgedacht und oben wohl einen völlig falschen Ansatz gehabt. Im Gegensatz zu den Google-Fonts werden die Inhalte aus der DB ja im JavaScript selbst angefordert, also kann das mit dem EventListener gar nicht funktionieren. Ist eventuell das gesamte Script falsch aufgebaut?

  • Nein, es ist nicht so, dass das ganze Skript falsch aufgebaut ist. Nur ist in diesem Fall der Ansatz mit dem Eventlistener nicht anwendbar. Die Frage und die Antworten werden ja durch Ajax geladen und dort hast Du schon einen Callback für den Fall, dass die Antwort vom Server da ist. Wenn Du dann das HTML fertig aufgebaut hast, kannst Du die Berechnung(en) mit Javascript durchführen:

    Dazu noch eine Bemerkung: In vielen, nicht allen, Fällen sind solche Berechnungen von Abmessungen mit Javascript nicht notwendig weil man das Ziel auch mit CSS erreichen kann. Mach doch Mal eine statische Demo von dem Layout und beschreibe, was Du erreichen willst. Dann kann man prüfen, ob es auch mit CSS geht.

  • Wenn ich die Berechnung auf o. g. Zeile 17 durchführe, bekomme ich vier unterschiedliche Werte, von denen keiner etwas mit der Höhe des Divs zu tun hat. Liegt wohl an der Schleife für die vier Buttons.


    Den richtigen Wert bekomme ich, wenn ich die Berechnung erst mit dem EventListener für den Klick auf einen der Button durchführe. Das ist dann aber zu spät, denn ich hätte den Wert gern schon vor dem ersten Klick.


    Eine statische Demo habe ich im Grunde schon in #130 abgelegt: http://music-quiz.bplaced.net/test01/


    Die beiden Divs playpart und redOverlay sollen dieselbe Höhe bekommen. Der Wert dieser Höhe wird gleichzeitig als negatives Margin für redOverlay benutzt, damit es zunächst unsichtbar ist. Nach Klick auf einen Button wird eine CSS-Transition hinzugefügt, die das rote Overlay (gefüllt mit entsprechendem Text) dann nach unten sliden lässt.


    Die Höhe des Divs playpart ist nicht vorhersehbar, sondern abhängig von Faktoren wie Bildschirmbreite und vom User gewählter Schriftgröße, also wollte ich das gern mit Javascript sicherstellen. Ganz einfach, dachte ich mir anfangs ... ;)


    Und natürlich darf eins nicht fehlen: das Danke Sempervivum !

  • Du hast Recht, ich hatte da zwei Dinge nicht bedacht:

    1. Das HTML ist erst vollständig fertig nach der Schleife.

    2. Das DOM einschl. der Abmessungen wird nicht sofort aktualisiert während das Javascript durchläuft. Man muss mit setTimeout einen kurzen Moment warten, dann sind die endgültigen Abmessungen verfügbar.

    Code
    1. }); // Ende des inneren Ajax
    2. }); // Ende des Eventlisteners
    3. } Ende der Schleife
    4. setTimeout(function() {
    5. // hier die Abmessungen berechnen
    6. }, 10);
    7. }); // Ende des äußeren Ajax
    8. } // Ende der Funktion


    Zitat

    Nach Klick auf einen Button wird eine CSS-Transition hinzugefügt, die das rote Overlay (gefüllt mit entsprechendem Text) dann nach unten sliden lässt.

    So etwas hatte ich schon vermutet, und das ist in der Tat ein Grund, relative Positionierung zu verwenden. Ich versuche mal, eine Alternative ohne Javascript heraus zu finden.

  • Herzlichen Dank – 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.


    Ich bin gespannt, ob das Ganze auch ohne JavaScript funktionieren würde, aber Du musst Dich nicht wirklich bemühen. Ich mache das hier ja zur zum Üben und komme auch erst wieder in einigen Tagen dazu …

  • Hier die klassische Variante mit absoluter Positionierung, Javascript nur noch für den Eventlistener auf den Button:

  • Man kann jedoch auch mit Gridlayout eine Überlappung erzeugen, siehe hier:

    https://mastery.games/post/overlapping-grid-items/

    Damit und mit Verschiebung durch transform: translate; sieht es dann so aus: