Flowers79: Javascript Problem bei mehrere ID's

Hallo erstmal Ich habe ein Problem mit ein JS für einen countdown. Er soll bei jeder ID den countdown anzeigen was über eine php Abfrage mit MySQL angezeigt wird und dann in ein template angezeigt wird. Das Script funktioniert tadellos bei nur eine ID, aber bei mehrere ID's funktioniert es nur bei eine ID, die andere bleiben stumm Hier den Code von der html. Ach so allesandere was aufgelistet werden soll wie zb ID,bild usw.. funktioniert bei mehrere ID's

<!-- IF challenges.TDABEI == 1 -->
 <script type="text/javascript">
var finalEventDt = new Date("{challenges.TSTATUS}").getTime();


var x = setInterval(function() {
  var now = new Date().getTime();
    
  var delay_total = finalEventDt - now;
    
  var days = Math.floor(delay_total / (1000 * 60 * 60 * 24));
  var hours = Math.floor((delay_total % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  var minutes = Math.floor((delay_total % (1000 * 60 * 60)) / (1000 * 60));
  var seconds = Math.floor((delay_total % (1000 * 60)) / 1000);
    document.getElementById("example").innerHTML = days + " Tage " + hours + " Stunden "
  + minutes + " minuten " + seconds + " sekunden "; 
	 
  if (delay_total < 0) {
    clearInterval(x);
    document.getElementById("example").innerHTML = "Spielzeit abgelaufen";


	}
}, 1000);
</script>
 
                    <td class="arcade-cvm" id="example">{challenges.TSTATUS}</td>
   <!-- ENDIF --> 

Was habe ich falsch gemacht im Javascript?

  1. Hallo Flowers79,

    wenn Du uns die Instanz der Seite mit nur einer Challenge zeigst, dürfte sich das Problem nicht offenbaren. Ich nehme an, dass Du den Code ungeschickt generierst und sich die Variablen gegenseitig überschreiben.

    Die elegantere Lösung dürfte sein, das Ablaufdatum am jeweiligen Ausgabefeld als data-Attribut zu hinterlegen und dann ein einziges JavaScript-Stück zu schreiben, das über alle Ausgabefelder läuft und den neuen Stand darin anzeigt.

    Gibt es diese Seite mit mehreren Challenges darauf online zu sehen?

    Rolf

    --
    sumpsi - posui - obstruxi
  2. @@Flowers79

    Das Script funktioniert tadellos bei nur eine ID, aber bei mehrere ID's funktioniert es nur bei eine ID, die andere bleiben stumm […]

    Was habe ich falsch gemacht im Javascript?

    Wenn du auf auf einer Webseite verschiedene Elemente dieselbe ID haben, dann hast du im HTML was falsch gemacht.

    IDs müssen einmalig sein. Das steckt im Konzept „Identität“ drin.

    Wenn zwei Geldscheine dieselbe Nummer haben, dann ist auch was faul. Genauso ist es mit HTML-Elementen.

    Wenn du mehrere Elemente hast, die sich in gewissen Dingen gleichen (wie z.B. alle 10-Euro-Scheine), dann ordne diese derselben Klasse zu.

    In JavaScript kannst du dann alle Elemente einer Klasse aus dem DOM fischen: getElementsByClassName (Elements im Plural!) oder querySelectorAll (all).

    🖖 Живіть довго і процвітайте

    --
    Ad astra per aspera
    1. Hallo Gunnar,

      dachte ich zuerst auch, aber wenn andere Dinge, die ID bezogen sind, funktionieren, scheint er diesen Aspekt verstanden zu haben und jeweils eigene IDs zu erzeugen - das hier aber nicht zu beschreiben. Zumindest kommt mir das so vor.

      Drum frug ich nach Online-Beispiel.

      Rolf

      --
      sumpsi - posui - obstruxi
    2. Hallo Nein leider noch nicht online,ich teste es noch in ein testforum. Jeder ID hat aber eine andere Nummerierung und es funktioniert ja mit die andere Auflistungen. Bin leider keine Profi sondern fange gerade damit an, sorry. Wie geht das mit den data Attribut?

      Ich habe mal mit mein Handy ein Screenshot gemacht Screen

      1. Hallo Flowers79,

        Es geht nicht um's Aussehen, sondern um eventuelle Fehlermeldungen in der Konsole.

        Die kannst du natürlich auch selbst erkunden... drück F12 und schau dich in den Entwicklertools um. Oder hast du schon?

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hi Ja im konsolenmodus sehe ich nichts verdächtiges. Ich habe gedacht ich hätte einen Fehler im Script aber ist dann wohl noch mehr. Hatte mal was gelesen von var = row......

          1. Hallo Flowers79,

            Hatte mal was gelesen von var = row......

            Was auch immer Du da gelesen hast, der Kontext erschließt sich mir leider nicht. Buchstäblich gelesen wäre das auch ein Syntaxfehler, weil var ein Schlüsselwort ist, dem Du nichts zuweisen kannst…

            Aber okay, wenn Du uns nichts Handfestes vorzeigen kannst, dann kann ich auf dein Problem nicht eingehen. Ich könnte Dir aber was zeigen.

            Vorschlag: Generiere die Spalte mit dem Ablaufzeitpunkt so:

            <table>
            <tr>...<td data-ablauf="1699632600">10.11.2023 17:10:00</td></tr>
            <tr>...<td data-ablauf="1704106800">01.01.2024 12:00:00</td></tr>
            </table>
            

            Im data-Attribut steht der UTC Wert des Zeitpunkts, und im Textinhalt der Zelle steht die Zeit so, dass ein Mensch sie versteht. Ganz wichtig: Es muss die UTC-Zeit sein, sonst bist Du bei Übergängen zwischen Sommer- und Winterzeit um eine Stunde daneben. Die UTC-Zeit bekommst Du in PHP, wenn Du ein DateTime-Objekt $d hast, entweder über $d->format("U") (großes U) oder über $d->getTimestamp().

            Am Ende der Seite (sonst startet es zu früh) platzierst Du dieses Script:

            <script>
            setInterval(refreshTimers, 1000);
            refreshTimers();
            
            const dayMilliseconds = 24 * 60 * 60 * 1000;
            
            function refreshTimers() {
              let jetzt = Date.now();
            	for (let timeCell of document.querySelectorAll("[data-ablauf]")) {
                let t = parseInt(timeCell.dataset.ablauf)*1000;
                if (t < jetzt) {
                  timeCell.textContent = "vorbei";
                }
                else {
                 	let restZeit = Math.floor(t - jetzt),
                      restDate = new Date(restZeit % dayMilliseconds);
                  timeCell.textContent = Math.floor(restZeit / dayMilliseconds) + " Tage, " +
                                         restDate.getHours() + " Stunden, " +
                                         restDate.getMinutes() + " Minuten, " +
                                         restDate.getSeconds() + " Sekunden";
                }
              }
            }</script>
            

            Was passiert da?

            setInterval kennst Du, ich verwende aber keine Inline-Funktion, sondern eine eigenstände Funktion, damit ich sie einmal sofort aufrufen kann. Ansonsten würde es eine Sekunde dauern, bis die Tage-Stunden-Minuten-Sekunden Darstellung erscheint.

            Mit const erzeugt man eine benannte Programmkonstante. dayMilliseconds enthält die Dauer eines Tages in Millisekunden (→ Wiki).

            document.querySelectorAll("[data-ablauf]") - die querySelectorAll-Methode ermittelt alle HTML Elemente, auf die der CSS-Selektor zutrifft, den man übergibt (→ Selfhtml Wiki). [data-ablauf] ist ein Attribut-Selektor (→ Wiki), d.h. er findet alle Elemente, die ein Attribut namens data-ablauf haben.

            Die Schleife for (let timeCell of ...) ist die sogenannte Iterator-Schleife, damit kann man alle Objekte durchlaufen, die die "Iterator"-Schnittstelle unterstützen (→ Wiki). Dazu gehören Arrays, aber auch die von querySelectorAll zurückgegebene NodeList. Das let vor timeCell ist das normale let für Variablendeklarationen, das ich auch für jetzt verwendet habe und wobei es sich um die moderne Version von var handelt (→ Wiki).

            Im Schleifenrumpf lese ich den Wert des data-Attributs aus, dafür verwendet man die dataset-Eigenschaft. dataset.ablauf liest den Inhalt des data-ablauf Attributs. Darauf wende ich parseInt an, um eine Zahl draus zu machen, und multiplizere mit 1000, weil ich im Beispiel-HTML UTC-Sekunden verwendet habe, JavaScript aber mit Millisekunden hantiert. Du kannst genausogut auch in PHP gleich die Millisekundenwerte erzeugen und brauchst dann im JavaScript nicht mehr mit 1000 zu multiplizieren.

            Dann prüfe ich, ob der Zeitpunkt schon vorbei ist. Wenn nicht, wird die Restzeit berechnet. Hier verwende ich einen netten Trick - mit new Date(restZeit % dayMilliseconds) bekomme ich ein Date-Objekt, das die Stunden, Minuten und Sekunden der Restzeit enthält. Dass daraus der 01.01.1970 wird, ist mir egal. Die Tage bestimme ich dann durch Division durch dayMilliseconds und floor, die Stunden, Minuten und Sekunden bekomme ich vom restDate-Objekt.

            Das passiert einmal pro Sekunden und für jede Zelle mit data-ablauf Attribut. Nix mit IDs nötig.

            Rolf

            --
            sumpsi - posui - obstruxi
            1. Super werde ich heute abend mal testen. Schon mal danke

            2. @@Rolf B

              Vorschlag: Generiere die Spalte mit dem Ablaufzeitpunkt so:

              <table>
              <tr>...<td data-ablauf="1699632600">10.11.2023 17:10:00</td></tr>
              <tr>...<td data-ablauf="1704106800">01.01.2024 12:00:00</td></tr>
              </table>
              

              Im data-Attribut steht der UTC Wert des Zeitpunkts, und im Textinhalt der Zelle steht die Zeit so, dass ein Mensch sie versteht.

              Nein, in deinem data-Attribut steht ein timestamp, nichts mit UTC.

              Kann man aber machen:

              <table>
                <tr>...<td><time datetime="2023-10-01T17:10Z">01.10.2023 19:10</time></td></tr>
                <tr>...<td><time datetime="2023-12-31T23:30Z">01.01.2024 00:30</time></td></tr>
              </table>
              

              HTML sieht dafür das time-Element mit datetime-Attribut vor.

              Im Gegensatz zum maschinenlesbaren Timestamp ist die Angabe im ISO-8601-Format sowohl maschinen- als auch menschenlesbar.

              Ganz wichtig: Es muss die UTC-Zeit sein, sonst bist Du bei Übergängen zwischen Sommer- und Winterzeit um eine Stunde daneben.

              Nö, muss nicht. Wichtig ist, dass die Zeitzone korrekt angegeben ist. Das kann genauso gut auch so sein:

              <table>
                <tr>...<td><time datetime="2023-10-01T19:10+02:00">01.10.2023 19:10</time></td></tr>
                <tr>...<td><time datetime="2024-01-01T00:30+01:00">01.01.2024 00:30</time></td></tr>
              </table>
              

              Die UTC-Zeit bekommst Du in PHP, wenn Du ein DateTime-Objekt $d hast, entweder über $d->format("U") (großes U) oder über $d->getTimestamp().

              Nö. Die Angabe in UTC bekommst du in PHP über $d->format('c') (kleines c).

              🖖 Живіть довго і процвітайте

              --
              Ad astra per aspera