Das liegt daran, dass das HTML überschrieben wird und dabei gehen die Eventlistener verloren. Du wirst auch das Registrieren für diese hinzu fügen müssen, ab Zeile 60. Hier offenbaren sich die Vorteile wenn man widerkehrenden Code in Funktionen packt.
Beiträge von Sempervivum
-
-
Das Problem ist, dass die Frage mit den Antworten auch neu aufgebaut werden muss, sonst läuft das i = 0; ins Leere:
Code
Alles anzeigendocument.getElementById('repeater').addEventListener('click', () => { document.getElementById('question').style.display = 'block'; document.getElementById('answer').style.display = 'block'; document.getElementById('oneMoreTime').style.display = 'none'; i = 0; // Das Folgende unbedingt in eine Funktion auslagern, // denn jetzt haben wir diesen Block schon drei Mal: document.getElementById('countQa').innerHTML = questions.length; document.getElementById('one').innerHTML = '1. Frage'; document.getElementById('two').innerHTML = questions[0].two; document.getElementById('three').innerHTML = questions[0].three; document.getElementById('four').innerHTML = questions[0].four; document.getElementById('five').innerHTML = questions[0].five; document.getElementById('six').innerHTML = questions[0].six; })Wie ich schon in dem Kommentar geschrieben habe, schreit das natürlich danach, in eine Funktion ausgelagert zu werden, dann jetzt haben wir diesen Codeblock schon drei Mal.
-
Wenn ich das ausprobiere habe ich eher den Eindruck, dass es nicht weiter geht nach einer falschen Antwort anstatt dass ich heraus fliege. Weiter komme ich dann nur, wenn ich die Seite neu lade und dann geht es natürlich wieder mit der ersten Frage los.
-
Zitat
Nach Zeile 85 steht noch mal dasselbe wie oben, und das nur, weil ich die Ausgabe einmal vor dem Eventhandler brauche und dann beliebig oft danach.
So etwas kann man meistens lösen indem man den wiederholten Code in eine Funktion auslagert und diese dann mehrfach aufruft.
-
Eines hast Du ja schon sehr richtig gemacht: Ein Array verwendet und nur einen Satz von Funktionen anstatt den Code zu vervielfachen wie es viele Anfänger tun.
Was mir sofort ins Auge springt ist die Tatsache, dass sich das immer gleiche HTML im Array wiederholt. Das würde ich als erstes angehen.
Also das HTML nur ein Mal statisch anlegen und darin die Teile, die sich verändern, mit Javascript austauschen:
HTML
Alles anzeigen<div id="wr-question"> <!-- In die beiden Spans die Nummer und den Text der Frage eintragen: --> <p><span id="nr-question"></span>.Frage</p> <p><span id="question"></span></p> </div> <div id="wr-answers"> <!-- In die p-Elemente jeweils den Text der Antwort eintragen: --> <input type="radio" name="fourQuestions"> <p id="answer1"></p> <input type="radio" name="fourQuestions"> <p id="answer2"></p> <input type="radio" name="fourQuestions"> <p id="answer3"></p> <input type="radio" name="fourQuestions"> <p id="answer4"></p> <i class="fas fa-smile"></i> Richtig! Du bist gut ... <i class="fas fa-sad-tear"></i> Das war wohl nichts ... <button id="button">nächste Frage</button> <div id="end">Das war's!</div> </div>Und das Array mit den Daten so:
JavaScriptconst questions = [ { question: 'Welche Band veröffentlichte 1980 das Album "Paris"?', answers: ['Queen', 'Visage', 'Supertramp', 'ELO'], isCorrect: [false, false, true, false] }, ];Wenn Du das so aufziehst, kannst Du darauf verzichten, die Eventlistener bei jedem Klick neu zu registrieren.
Das Javascript dazu zu schreiben überlasse ich dir. Wenn Du nicht zum Ziel kommst, melde dich wieder.
Auch in diesem Fall kann man sich andere Varianten überlegen. Was sich ebenfalls anbieten würde, ist, mit Templates zu arbeiten, d. h. im HTML Platzhalter einzubauen und diese dann gegen die aktuellen Werte auszutauschen. Für solche Platzhalter benutzt man häufig doppelte geschweifte Klammern: {{name}} weil diese normaler Weise im HTML nicht vorkommen.
Dafür gibt es auch Bibliotheken, die es vereinfachen. Vor längerer Zeit habe ich z. B. Handlebars kennen gelernt aber ich weiß nicht, ob das noch aktuell ist.
-
PPS: Wie ich sehe, lädst Du nur einen Ausschnitt der Datei verzeichnis.php. Heißt das, dass die Masterseite auch verzeichnis.php ist?
-
PS: Hast Du das online, dass man es sich im Zusammenhang ansehen kann?
-
Dann stehe ich ratlos davor. Bei mir funktioniert es, Öffnen mit Button, Schließen mit Javascript.
Bei der Fehlermeldung steht: "verzeichnis.php". Das irritiert mich, mit verzeichnis.php lädst Du doch die Tabelle neu?
-
Hast Du auch das Javascript von Bootstrap eingebunden? Ich habe mit BS Version 4 getestet, hast Du auch diese Version?
-
Ich habe das mal getestet und bei mir funktioniert es einwandfrei. Wie legst Du denn das HTML des Modals an? Wenn man es statisch in das übrige HTML schreibt ist es zunächst nicht sichtbar und man muss es mit open öffnen. Wie machst Du das?
Zitatdie restlichen Funktionen wie "Destroy" und "refreshData" funktionieren dann auch nicht mehr.
Das weist darauf hin, dass irgend wo ein Syntaxfehler steckt. Sagt die Console etwas dazu?
-
Das Skript sortiert nach Dateinamen, d. h. diese müssen in irgendeiner Form die Zeit des Speicherns angeben.
$images[0] ist dann das älteste und end($images) das neueste Bild.
-
Prüfe, ob dir die Doku hilft:
https://getbootstrap.com/docs/4.0/components/modal/#methods
Du brauchst hier die Funktion hide.
Wenn Du nicht zum Ziel kommst, melde dich wieder.
-
Möglicher Weise hilft die Doku:
https://www.php.net/manual/de/function.session-unset.php
Beachte auch den obersten Beitrag unter "User Contributed Notes".
-
Genau verkehrt herum, Du musst die Tabelle erst laden und dann initialisieren. Und dabei berücksichtigen, dass das Laden einen kurzen Moment dauert, daher die Initialisierung im Callback des load:
-
-
Was das Problem mit Datatables betrifft, so vermute ich, dass Du mit dem jQuery-load die Tabelle komplett überschreibst. Dabei bleibt aber alles, was Datatables hinzu gefügt hat und was außerhalb der Tabelle liegt, erhalten.
Informiere dich über die Funktion destroy:
https://datatables.net/reference/api/destroy()
zerstöre damit die Tabelle vor dem Aktualisieren, dann lade sie mit deinem jQuery-load neu und initialisiere sie wieder.
Eleganter wäre es, die Tabelle mit dem eingebauten Ajax von Datatables zu laden, denn dann könntest Du sie einfach mit reload neu laden, siehe hier:
https://datatables.net/reference/api/ajax.reload()
Aber dazu wären wahrscheinlich einige Anpassungen auch am PHP-Skript nötig, weil es dann JSON statt HTML liefern muss.
-
Zitat
Dann bleibt alles am Breakpoint stehen.
Das ist ja genau was wir wollten.
ZitatBeim Fortsetzen steht in der Konsole "[Violation] 'click' handler took 9070ms"
kenne ich von meinem Browser (Opera) bzw. dessen Debugger nicht. Anscheinend hat deiner da einen Mechanismus eingebaut, um überlange Laufzeiten von Eventhandlern abzufangen, weil dadurch der Browser blockiert wird. Allerdings müsste es dann einen Weg geben, um das beim Debuggen auszuschalten, denn da ist es ja normal, dass man eine ganze Zeit lang am Haltepunkt steht.
Welchen Broser benutzt Du?
-
-
Gut, dass Du dieses GIF angehängt hast, daran erkennt man nämlich, dass das ein Missverständnis ist und das Verhalten normal. Es geht ja um diesen Code:
Code
Alles anzeigen// Mit der folgenden Zeile wird der Eventlistener registriert: document.getElementById('clicker').addEventListener('click', () => { // Ab hier beginnt das Innere der anonymen Funktion. Hier gelangt man erst hin wenn das Event feuert // und die Funktion aufgerufen wird, beim Laden der Seite jedoch noch nicht. Setze auf die folgende // Zeile einen Haltpunkt, dann kannst Du dich davon überzeugen. if (status === 'showQuestion') { document.getElementById('questionAnswers').innerHTML = '<p>' + questionsAndAnswers[counter].question + '</p>'; status = 'showAnswer'; document.getElementById('clicker').classList.remove('blink'); document.getElementById('clicker').style.backgroundColor = 'dodgerblue'; document.getElementById('lastwords').classList.remove('morecolor'); document.getElementById('questionAnswers').classList.remove('hidden'); document.getElementById('questionAnswers').classList.remove('lesscolor'); let question = 'zur ' + (counter + 1) + '. Antwort'; document.getElementById('clicker').innerHTML = question; } else { document.getElementById('questionAnswers').innerHTML = '<p>' + questionsAndAnswers[counter].answer + '</p>'; status = 'showQuestion'; document.getElementById('clicker').style.backgroundColor = 'teal'; let answer = 'zur ' + (counter + 2) + '. Frage'; document.getElementById('clicker').innerHTML = answer; counter++; if (counter === questionsAndAnswers.length && status === 'showQuestion') { counter = 0; document.getElementById('clicker').innerHTML = 'Ende!'; function myTimeout1() { document.getElementById('lastwords').style.display = 'inline-block'; } function myTimeout2() { document.getElementById('lastwords').classList.add('morecolor'); document.getElementById('questionAnswers').classList.add('lesscolor'); } function myTimeout3() { document.getElementById('clicker').innerHTML = again; } function myTimeout4() { document.getElementById('clicker').style.backgroundColor = 'none'; document.getElementById('clicker').classList.add('blink'); } const sequence = [ { // Die Zeit, um die der Aufruf der Funktion (callback) // verzögert werden soll: delay: 50, // Die Funktion, die aufgerufen werden soll: callback: myTimeout1 }, { delay: 500, callback: myTimeout2 }, { delay: 3000, callback: myTimeout3 }, { delay: 1500, callback: myTimeout4 }, ]; // Bearbeitet jeweils einen Eintrag im Array sequence: function doIt() { // Die aktuelle Aktion wird nach der gewünschten Verzögerung ausgeführt: timer = setTimeout(() => { // Die Funktion aufrufen, die im aktuellen Datensatz in dem Array // sequence als callback eingetragen ist, z. B. myTimeout2 // beim zweiten Datensatz: sequence[idx].callback(); // Index für das Array sequence erhöhen: idx++; // Sind wir noch nicht am Ende des Arrays sequence angelangt? if (idx < sequence.length) { // Den aktuellen Eintrag im Array (nach Erhöhen des Index) // bearbeiten: doIt(); console.log(timer) } }, sequence[idx].delay) // Der zweite Parameter beim Aufruf der Funktion setTimeout ist die Verzögerungszeit. // Diese ist im Array sequence unter delay eingetragen, z. B. 500 // beim zweiten Datensatz. } let // Wir beginnen mit dem ersten Datensatz in sequence, // also den Index auf 0 setzen: idx = 0, // Timervariable, hier wird die ID des aktuellen Timers // gespeichert, wir brauchen sie, um den Timer abbrechen zu können: timer; // Jetzt beginnen wir die Sequenz durch den Aufruf der Funktion doIt: doIt(); document.getElementById('clicker').addEventListener('click', () => { if (timer) { clearTimeout(timer); } }); } } }); // Hier ist jetzt das Registrieren des Eventlisteners beendet und wenn // weitere Anweisungen vorhanden wären, würde der Debugger beim Stepping // dort wieder anhalten.Ich habe wieder Kommentare hinein geschrieben, nur am Anfang und am Ende, dazwischen wollte ich nicht löschen, um mit den Klammern nicht durcheinander zu kommen.
-
Dann vermute ich, dass an dem Wert von data.posKran noch eine Maßeinheit daran hängt und es kein Integer ist. Was wird denn in #posKran genau ausgegeben?