fatal_error: Formular absenden nach Ablauf des Countdowns

Hi, ich arbeite im Moment an einem Quiz. Um den Schwierigkeitsgrad zu erhöhen, soll man genau 60 Sekunden Zeit haben, um die Frage zu lösen (Dieser Countdown soll auch angezeigt werden.). Danach soll das Formular automatisch abgeschickt werden. Hier erstmal der HTML Code:

<p id='timer'></p>
<form action='auswertung.php' method='post'>
  <input class='button' type='submit' id='submitb' value='weiter'>
</form>

Mein eigentliches Problem ist der Countdown. Ich habe hier versucht mit einer for-Schleife zu arbeiten, weiß aber nicht ob ich es überhaupt richtig gemacht hab. Bis jetzt bekomme ich immer die Fehlermeldung: TypeError: null is not an object (evaluating 'document.getElementById('submitb').click') und der Countdown wird nicht im <p> tag angezeigt.

 for (var i = 60; i=0; i--) {
    document.getElementById('timer').innerHTML = 'i';
    setTimeout(1000);
    
  }
      document.getElementById('submitb').click();
 

Aber wenn ich die Schleife weglasse funktioniert das Senden mit onload oder onclick.

document.getElementById('submitb').click();

Ich würde mich freue wenn jemand mir folgende Fragen beantworten könnte: Ist die For-Schleife so überhaupt richtig? Wie kann ich den Countdown anzeigen lassen? Und Warum bekomme ich die oben genannte Fehlermeldung?

Im Voraus schonmal vielen Dank.

  1. @@fatal_error

     for (var i = 60; i=0; i--) {
        document.getElementById('timer').innerHTML = 'i';
        setTimeout(1000);
        
      }
    

    Pack da doch mal eine Kontrollausgabe wie console.log('loop') rein um zu sehen, wie oft die Schleife denn durchlaufen wird.

    Du könntest überrascht sein.

    Der Abschnitt im Wiki-Artikel beginnt verwirrend: „Die Schleifenbedingung einer for-Schleife sieht von vorne herein einen Zähler und eine Abbruchbedingung vor.“

    Nein, keine Abbruchbedingung.

    Weiter im Text steht’s dann richtig: „Die zweite Anweisung enthält die Bedingung für den Schleifenablauf; die Schleife wird ausgeführt, wenn und solange diese zutrifft.“ (Hervorhebung von mir.)

    LLAP 🖖

    --
    “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
    1. Hallo Gunnar Bittersmann,

      Der Abschnitt im Wiki-Artikel beginnt verwirrend:

      begann.

      Bis demnächst
      Matthias

      --
      Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
    2. @@Gunnar Bittersmann

       for (var i = 60; i=0; i--) {
          document.getElementById('timer').innerHTML = 'i';
          setTimeout(1000);
          
        }
      

      […] wie oft die Schleife denn durchlaufen wird.

      Wenn du das mit der Schleife hinbekommen hast, wirst du merken, dass das immer nocht nicht läuft. setTimeout() geht anders: „Diese Funktion erwartet zwei oder mehr Parameter: …“

      Statt setTimeout() bietet sich hier aber auch an, setInterval() und clearInterval zu verwenden.

      LLAP 🖖

      --
      “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
    3. Edit: Parallelpost zu Gunnar :)

      Dein Code hat gleich mehrere Probleme. Nur den Type Error hat er eigentlich nicht, DEN kann ich nicht nachvollziehen. Das muss etwas sein, das im Kontext deiner Seite stattfindet aber hier nicht sichtbar ist.

      Zum einen: manche Abfragen sind gleicher als andere. Ich will Dir Gunnars Quiz aber nicht verderben. Du kommst bestimmt selbst drauf. Generation von C Programmierern haben diesen Fehler schon vor Dir gemacht.

      Zum zweiten: Zuweisen von 'i' an das Zeitanzeigefeld ergibt die Zeichenkette 'i' und nicht den Wert der Variablen i. Verwende i.toString(). Bzw. etwas anderes, siehe unten.

      Zum dritten ist setTimeout keine Funktion zum Warten in einer Schleife. Diese Denke funktioniert in JavaScript nicht. JavaScript ist wie eine heiße Kartoffel: Anpacken, schnell damit hantieren und wieder weg damit. Denn solange ein Script läuft, blockiert der Browser.

      Mit setTimeout registriert man eine Funktion, die nach Ablauf einer gewissen Zeit aufgerufen werden soll. Um einen kontinuierlichen Aufruf im Sekundentakt zu erreichen, kann diese Funktion sich zum Schluss selbst erneut mit setTimeout zum Aufruf registrieren.

      Einfacher ist es aber, setInterval zu verwenden, damit registriert man eine Funktion zum ständigen Neuaufruf in einem bestimmten Zeitabstand. Normalerweise müsste man diese Funktion auch wieder deregistrieren, aber wenn Du dein Form submittest, wird die Seite neu geladen und damit werden registrierte Intervallfunktionen entfernt.

      Deine Zeitanzeige wird nun aber unregelmäßig springen. Das liegt daran, dass ein Intervall von 1000 Millisekunden nie genau eingehalten wird. Du solltest 100ms als Intervallzeit setzen. Vorher speicherst Du Dir in einer Variablen startZeit = Date.now(). In der Intervall-Funktion berechnest Du laufZeit = (Date.now()-startZeit)/1000. Die kannst Du mit 60 vergleichen, und für die Anzeige der Restzeit gibst Du Math.floor(60-laufZeit) aus.

      So, ich hoffe, damit hast Du genug Ideen für eine erfolgreiche Umsetzung :)

      Rolf

  2. moin,

     for (var i = 60; i=0; i--) {
        document.getElementById('timer').innerHTML = 'i';
        setTimeout(1000);
        
      }
    

    Ist die For-Schleife so überhaupt richtig?

    So überhaupt nicht. Sie wird gar nicht erst anlaufen, weil mit i=0 die Abbruchbedingung bereits erfüllt ist (Zuweisung ist wahr). /pl

    1. @@pl

      So überhaupt nicht.

      Oh ja. Zuweisungsoperator = vs. Vergleichsoperator == oder === auch noch.

      Sie wird gar nicht erst anlaufen, weil mit i=0 die Abbruchbedingung bereits erfüllt ist (Zuweisung ist wahr).

      Hier irrst du – doppelt.

      Zum einen ist der Rückgabewert einer Zuweisung der Wert rechts vom Gleichheitszeichen, in dem Fall also 0, ein falsy value.

      !!(i = 0); // false
      

      Zum anderen ist – wie ich bereits zu verstehen gab – die Bedingung bei for-Schleifen in JavaScript (und allen anderen an C angelehnten Sprachen) keine Abbruchbedingung.

      Der doppelte Irrtum führt dazu, dass du darin recht hast, dass die Schleife gar nicht erst anlaufen wird.

      LLAP 🖖

      --
      “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
    2. Ist die For-Schleife so überhaupt richtig?

      So überhaupt nicht. Sie wird gar nicht erst anlaufen, weil mit i=0 die Abbruchbedingung bereits erfüllt ist (Zuweisung ist wahr). /pl

      Spielverderber ;-)

    3. Hi,

      So überhaupt nicht. Sie wird gar nicht erst anlaufen, weil mit i=0 die Abbruchbedingung bereits erfüllt ist (Zuweisung ist wahr).

      Nein. Der Wert einer Zuweisung ist in Javascript der zugewiesene Wert.
      Schreib
      javascript:alert(i=42)
      in die Adreßzeile des Browsers und drück return.

      Der Wert von i=0 ist also 0. Das wird als false interpretiert.

      Außerdem gibt es bei einer for-Schleife keine Abbruch-Bedingung, wie hier im THread schon erwähnt wurde. Die Schleife wird so lange ausgeführt, wie die Bedingung wahr ist.

      Deine beiden Irrtümer heben sich hier zufällig wieder auf, die Schleife wird tatsächlich nicht durchlaufen. Aber Deine Begründung hat nichts mit der Realität zu tun.

      cu,
      Andreas a/k/a MudGuard

      1. @@MudGuard

        Deine beiden Irrtümer heben sich hier zufällig wieder auf, die Schleife wird tatsächlich nicht durchlaufen. Aber Deine Begründung hat nichts mit der Realität zu tun.

        Erster! 😜

        LLAP 🖖

        --
        “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
        1. Hi,

          Erster! 😜

          Immerhin nicht Letzer! ;-) Da ist noch einer nochmal 2 Minuten später ...

          cu,
          Andreas a/k/a MudGuard

      2. Außerdem gibt es bei einer for-Schleife keine Abbruch-Bedingung

        Soweit mir bekannt, kann man eine Schleife mit break abbrechen.

        1. @@Linuchs

          Außerdem gibt es bei einer for-Schleife keine Abbruch-Bedingung

          Soweit mir bekannt, kann man eine Schleife mit break abbrechen.

          Oder (wenn man sich innerhalb einer Funktion befindet) auch mit return.

          Oder auch durch Verlassen der Seite location.href = '…';

          LLAP 🖖

          --
          “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
      3. @@MudGuard

        Deine beiden Irrtümer

        Muss es im Plural nich „Irrten“ heißen?

        LLAP 🖖

        --
        “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
        1. Nein. Das Wort endet auf -um. Der Plural demzufolge auf -a. Das Irrtum, die Irrta. Ganz einfach für den geübten Latainer.

          1. @@Rolf b

            Nein. Das Wort endet auf -um. Der Plural demzufolge auf -a. Das Irrtum, die Irrta. Ganz einfach für den geübten Latainer.

            Jetzt kommt der mit seinem großen Latrinum!

            LLAP 🖖

            --
            “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
        2. @@MudGuard

          Deine beiden Irrtümer

          Muss es im Plural nich „Irrten“ heißen?

          Pluralierung ist ganz einfach: Hänge ein 's' an den Einzeiler! Beispiele:

          • Kuh => Kuhs
          • Ei => Eis
          • usws.

          MfGs

          1. Tach!

            Pluralierung ist ganz einfach: Hänge ein 's' an den Einzeiler!

            Das richtige Wort wäre Einzahler gewesen.

            dedlfix.

          2. @@pl

            Pluralierung ist ganz einfach: Hänge ein 's' an den Einzeiler! Beispiele:

            • Kuh => Kuhs

            Ausnahmsweise aber auch mal ein e:

            „Eine Kuh macht muh, viele Kühe machen Mühe“ (Agnes Kraus als Tante Alma in „Viechereien“)

            • Eis => Eisen, passt.

            LLAP 🖖

            --
            “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
            1. @@

              Pluralierung ist ganz einfach: Hänge ein 's' an den Einzeiler! Beispiele:

              • Kuh => Kuhs

              Ausnahmsweise aber auch mal ein e:

              „Eine Kuh macht muh, viele Kühe machen Mühe“ (Agnes Kraus als Tante Alma in „Viechereien“)

              Ja die Agnes, sie war ne liebe Frau. Hab se och mal jetroffen form Zoo -- 78 oder so.

              MfGs

              1. Hallo,

                Ja die Agnes, sie war ne liebe Frau.

                Eine? Da hängt doch ein 's' hinten dran; das müssen wohl mehrere Agne sein.

                Gruß
                Kalk

                1. Hi,

                  Eine? Da hängt doch ein 's' hinten dran; das müssen wohl mehrere Agne sein.

                  Wieso hast Du mehrere 'da' nach dem Semikolon? ;-)

                  cu,
                  Andreas a/k/a MudGuards

                  1. Hallo,

                    Eine? Da hängt doch ein 's' hinten dran; das müssen wohl mehrere Agne sein.

                    Wieso hast Du mehrere 'da' nach dem Semikolon? ;-)

                    Na, für jede Agne ein!

                    Gruß
                    Kalk

          3. Jetzt weiß ich endlich, warum es bei mir nie bei einem Glas bleibt, wenn ich Pils bestelle. Beim nächsten mal probiere ich es mit "ein Gla Pil", dann klappt das bestimmt besser mit dem Nachhauseweg.

            Rolf 🍺

    4. Tach!

      So überhaupt nicht. Sie wird gar nicht erst anlaufen, weil mit i=0 die Abbruchbedingung bereits erfüllt ist (Zuweisung ist wahr).

      Falsch. In dem Fall. Das Ergebnis einer Zuweisung ist der Wert, der zugewiesen wird. Bei false oder einem falsy Wert, wie 0, ist es false, bei true oder einem truthy Wert (alles was nicht 0 ist und eine Zahl ist) ist es true.

      Für den Probleminhaber: Eine Zuweisung = ist kein Vergleich ==.

      dedlfix.

  3. Hi, falls Du noch dran bist ?

    ich arbeite im Moment an einem Quiz. Um den Schwierigkeitsgrad zu erhöhen, soll man genau 60 Sekunden Zeit haben, um die Frage zu lösen (Dieser Countdown soll auch angezeigt werden.).

    Idee: Mach ein Feld und setze zum Zeitpunkt der Auslieferung der Seite eine 60 da ein. Evntl. lass den Besucher entscheiden wann er den Countdown startet.

    Dann starte eine Funktion die jede Sekunde auf dieses Feld zugreift, die 60 (sichtbar) runterzählt und bei 0 das Quiz beendet.

    Danach soll das Formular automatisch abgeschickt werden.

    Die Alternative (nicht automatisch senden) wäre zu überlegen.

    MfG, Code:

    <input id="cdown" value="60">
    <script>
    function countdown(){
        var cdown = document.getElementById('cdown');
        cdown.value = --cdown.value;
        if(cdown.value == 0){
            alert("Baz!");
            return;
        }
        window.setTimeout(countdown, 1000);
    }
    countdown();
    </script>
    
    1. @@pl

      function countdown(){
          var cdown = document.getElementById('cdown');
      

      Nein. Du bist doch schon lange genug hier dabei, dass du wissen solltest, dass man sich ein Element nicht in jedem Funktionsaufruf/Schleifendurchlauf erneut aus dem DOM raussuchen sollte. Das macht mal einmal am Anfang – außerhalb des Funktionsaufrufs/Schleifendurchlaufs.

          cdown.value = --cdown.value;
      

      Hier hast du wohl pures Glück, dass der Typecast wie gewünscht funktioniert. cdown.value ist vom Typ "string". Bei cdown.value = cdown.value + 1 erlebst du dein blaues Wunder.

          if(cdown.value == 0){
      

      Hier verlässt du dich darauf, dass der Typecast wie gewünscht funktioniert. Saubere Programmierung geht anders.

      LLAP 🖖

      --
      “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
      1. @@

        Nein. Du bist doch schon lange genug hier dabei, dass du wissen solltest, dass man sich ein Element nicht in jedem Funktionsaufruf/Schleifendurchlauf erneut aus dem DOM raussuchen sollte. Das macht mal einmal am Anfang – außerhalb des Funktionsaufrufs/Schleifendurchlaufs.

        Nein: Weil ich das produktiv übern Template machen würde. D.h., Variablen gibt es nur noch im Scope der jeweiligen Funktion.

        Hier hast du wohl pures Glück, dass der Typecast wie gewünscht funktioniert

        Produktiv: Siehe oben. Eine Funktion, ein Scope. Die ganze Progammlogik wird nicht mehr übers DOM geschleift sondern über ein oder mehrere Templates komplett vom DOM getennt.

        Guck mal im Beispiel wie einfach das dann wird. Skalierbar isses auch, ich kann das ohne Handstand nachrüsten auf eine bidirektionale Kommunikation mit dem Funksensor (falls der das unterstützt, wird die Rückmeldung einfach ins Template gerendert).

        MfG