Friedel: Anzahl der Zellen mit Javascript zählen

problematische Seite

Hallo

Ich möchte in der Tabelle negative Beträge in rot darstellen. Leider habe ich keine Möglichkeit gefunden, das mit CSS ohne JavaScript zu machen. Daher möchte ich es mit Javascript machen.

Dazu möchte ich alle Zellen der Tabelle mit einer Schleife durchlaufen, den Inhalt auslesen, prüfen ob er mit einem Minuszeichen gefolgt von einer Zahl anfängt, und der Zelle dann die Klasse class="red" verpassen.

Aber es ist lange her, dass ich Sripte geschrieben habe und offensichtlich habe ich mehr verlernt, als ich dachte. Wie man an der Beispielseite sieht, kappt nicht mal das Zählen der Zellen. Warum gibt mir der altert "0" zurück?

  1. problematische Seite

    Hi,

    Aber es ist lange her, dass ich Sripte geschrieben habe und offensichtlich habe ich mehr verlernt, als ich dachte. Wie man an der Beispielseite sieht, kappt nicht mal das Zählen der Zellen. Warum gibt mir der altert "0" zurück?

    table hat eine rows-Eigenschaft …

    also eher document.getElementById("tabelle").rows.length;

    Auch zum Durchmarschieren kann man die rows- (und deren cells-Eigenschaft) benutzen.

    cu,
    Andreas a/k/a MudGuard

    1. problematische Seite

      Danke. Das hatte ich schon probiert, bin aber nicht weiter gekommen. Ursache war wohl (hoffentlich) der Fehler, der von Gunnar Bittersmann (26.09.2026 21:33) beschrieben wird. Wenn's so ist, werde ich auf diesen geplanten Weg zurückkommen.

  2. problematische Seite

    @@Friedel

    Warum gibt mir der altert "0" zurück?

    Da bin ich auch noch nicht ganz hintergestiegen, warum das alert() überhaupt ausgeführt wird.

    Dein Fehler ist:

    window.addEventListener('DOMContentLoaded', negativeWerte());
    

    Da weist du dem EventListener keine Handlerfunktion zu, sondern einen Funktionswert. Soll heißen: Die Klammern müssen weg.

    Aber was willst du überhaupt mit der Anzahl der Tabellenzellen? (Ich ahne Schlimmes.)

    BTW:

    let anzZellen = document.getElementsByTagName('tr').length;
    

    gibt dir nicht die Anzahl der Zellen, sondern die Anzahl der Zeilen. Und da sich diese nicht ändert, wäre const richtig, nicht let.

    BTW2: Ich würde vergessen, dass es getElementsByTagName() überhaupt gibt. Mit querySelectorAll() (bzw. querySelector()) hast du ein Interface für alle Anwendungsfälle.

    BTW3: Den EventListener kannst du dir sparen, wenn du das Script am Ende des body notierst; dann ist das DOM schon da.

    BTW4: Die Idee mit dem Klassifizieren ist vielleicht doch nicht die schlechteste. Dann musst du nämlich nicht alle Tabellenzellen durchgehen, sondern nur document.querySelctorAll('td.betrag').

    🖖 Live long and prosper

    --
    “Space: the final frontier. Above us. Around us. Within us.
    We have always looked to the stars to discover who we are.”

    — Michael Burnham in Star Trek: Discovery S2:E1
    1. problematische Seite

      Da weist du dem EventListener keine Handlerfunktion zu, sondern einen Funktionswert. Soll heißen: Die Klammern müssen weg.

      Danke. Die Klammern waren der Fehler. Dadurch haben all die vielen Versuche nicht funktioniert.

      Aber was willst du überhaupt mit der Anzahl der Tabellenzellen? (Ich ahne Schlimmes.)

      Das steht in dem Post, auf den du geantwortet hast. Was du ahnst, ahne ich allerdings nicht. Der Link hat daran nichts geänert.

      BTW:

      let anzZellen = document.getElementsByTagName('tr').length;
      

      gibt dir nicht die Anzahl der Zellen, sondern die Anzahl der Zeilen.

      Ja. Und solange die 0 war, waren alle weiteren Versuche sinnlos.

      Und da sich diese nicht ändert, wäre const richtig, nicht let.

      Stimmt. Da stand da auch schon mal. Kommt wieder hin.

      BTW2: Ich würde vergessen, dass es getElementsByTagName() überhaupt gibt. Mit querySelectorAll() (bzw. querySelector()) hast du ein Interface für alle Anwendungsfälle.

      querySelectorAll() und querySelector() kannte ich nicht. Das werde ich versuchen.

      BTW3: Den EventListener kannst du dir sparen, wenn du das Script am Ende des body notierst; dann ist das DOM schon da.

      Ja. Aber zum einen gehört er imho nicht ins Html, zum anderen wird die Html-Seite mindestens ein mal im Monat neu erstellt. Das Script soll immer gleich bleiben.

      BTW4: Die Idee mit dem Klassifizieren ist vielleicht doch nicht die schlechteste. Dann musst du nähmlich nicht alle Tabellenzellen durchgehen, sondern nur document.querySelctorAll('td.betrag').

      Doch, das ist imho eine sehr schlechte Idee. Dann muss ich nämlich ein mal im Monat jeweils mehrere 10000 Zellen händisch mit einer Klasse versehen.

      1. problematische Seite

        @@Friedel

        Aber was willst du überhaupt mit der Anzahl der Tabellenzellen? (Ich ahne Schlimmes.)

        Das steht in dem Post, auf den du geantwortet hast.

        Nein. Da steht: „Ich möchte in der Tabelle negative Beträge in rot darstellen. […] Dazu möchte ich alle Zellen der Tabelle mit einer Schleife durchlaufen […]“

        Um alle Zellen mit einer Schleife zu durchlaufen, musst du nicht deren Anzahl kennen. Und das steht auch in dem verlinkten Posting: for … of, forEach.

        🖖 Live long and prosper

        --
        “Space: the final frontier. Above us. Around us. Within us.
        We have always looked to the stars to discover who we are.”

        — Michael Burnham in Star Trek: Discovery S2:E1
        1. problematische Seite

          Hallo Gunnar,

          das steht auch in dem verlinkten Posting:

          Ich bin sicher, dass Du das irgendwo verlunken hattest, aber ich finde den Link tatsächlich nicht wieder.

          Daher zur Klarstellung:

          Die meisten JavaScript-Objekte, die Mengen repräsentieren, sind iterierbar, d.h. sie unterstützen das Iterator-Interface. Und jedes Objekt, das iterierbar ist, lässt sich mit der for...of Schleife durchlaufen, ohne dafür seine Größe kennen zu müssen. querySelectorAll liefert ein NodeList-Objekt, das iterierbar ist.

          for (const cell of document.querySelectorAll("td")) {
             // cell ist eins der td Elemente
          }
          

          Wenn Du eine betrag Klasse hast, kannst Du auch "td.betrag" verwenden, aber ich verstehe Dich so, dass dein LibreOffice-Export das nicht hergibt.

          Ich verstehe die Situation aber auch so, dass dieser Weg ungünstig ist. Das habe ich anderswo im Thread schon erwähnt: die Aufgabe sollte in der Toolchain beim Erstellen des HTML-Dokuments gelöst werden.

          Nochmal zu for...of: Was man dann nicht sofort weiß, ist, die wievielte Zeile oder Spalte das ist. Für die gestellte Aufgabe ist das irrelevant, aber jedes th oder td Element besitzt eine cellIndex-Eigenschaft, mit der man die Spaltennummer herausbekommt (beginnend mit 0), und da ein th- oder td-Element immer ein tr-Element als Elternelement hat, kommt man über cell.parentElement an das tr-Element heran und das hat eine rowIndex-Eigenschaft, die die Zeilennummer tabellenübergreifend liefert (beginnend mit 0), und eine sectionRowIndex-Eigenschaft, die die Zeilennummer innerhalb eines Tabellenabschnitts (thead, tbody, tfoot) liefert.

          Rolf

          --
          sumpsi - posui - obstruxi
          1. problematische Seite

            Hi,

            Nochmal zu for...of: Was man dann nicht sofort weiß, ist, die wievielte Zeile oder Spalte das ist. Für die gestellte Aufgabe ist das irrelevant, aber jedes th oder td Element besitzt eine cellIndex-Eigenschaft, mit der man die Spaltennummer herausbekommt (beginnend mit 0),

            so wie ich das verstehe, bekommt man damit heraus, das wievielte td/th-Element es in der tr ist. Was dank rowspan/colspan nicht notwendigerweise die Nummer der Spalte ist.

            Zitat von WhatWG:
            Returns the position of the cell in the row's cells list. This does not necessarily correspond to the x-position of the cell in the table, since earlier cells might cover multiple rows or columns.

            cu,
            Andreas a/k/a MudGuard

            1. problematische Seite

              Hallo MudGuard,

              du hast natürlich recht, dass man hier Spanning berücksichtigen muss.

              Wenn du möchtest, kann ich Dir weitere Details.... achso, ich bin ja keine KI 😉

              Eine Tabelle, die aus einem Spreadsheet herausgelutscht wurde, könnte durchaus Spans aufweisen. Sofern Libreoffice zusammengefügte Zellen als Spans exportiert.

              Rolf

              --
              sumpsi - posui - obstruxi
          2. problematische Seite

            @@Rolf B

            for (const cell of document.querySelectorAll("td")) {
               // cell ist eins der td Elemente
            }
            

            Ja, entweder so (Schachbrett 1) oder besser(?) – wie @MudGuard sagte – ohne Raussuchen aller Zellen aus dem DOM, weil es dafür Eigenschaften gibt (Schachbrett 2):

            for (const row of document.querySelector('table').rows) {
            	for (const cell of row.cells) {
            		// mach was mit cell
            	}
            }
            

            aber jedes th oder td Element besitzt eine cellIndex-Eigenschaft […] und das [tr-Element] hat eine rowIndex-Eigenschaft […] und eine sectionRowIndex-Eigenschaft

            Was es nicht alles gibt!

            🖖 Live long and prosper

            --
            “Space: the final frontier. Above us. Around us. Within us.
            We have always looked to the stars to discover who we are.”

            — Michael Burnham in Star Trek: Discovery S2:E1
            1. problematische Seite

              @@Gunnar Bittersmann

              entweder so (Schachbrett 1) oder [so] (Schachbrett 2)

              Ich hab die Serie noch um eine Variante Schachbrett 0 ergänzt, bevor noch jemand (völlig zurecht!) meint: also dafür braucht man doch kein JavaScript! 😊

              🖖 Live long and prosper

              --
              “Space: the final frontier. Above us. Around us. Within us.
              We have always looked to the stars to discover who we are.”

              — Michael Burnham in Star Trek: Discovery S2:E1
  3. problematische Seite

    @@Friedel

    prüfen ob er mit einem Minuszeichen gefolgt von einer Zahl anfängt,

    Das ist bei dir nirgends der Fall. ‚-‘ (U+002D) ist kein Minuszeichen (außer in Computersprachen); ‚−‘ (U+2212) ist eins.

    Das kannste in deiner Schleife gleich mit berichtigen:

    // ersetze Bindestriche durch Minuszeichen
    cell.textContent = cell.textContent.replace(/^-/, '\u2212');
    

    und der Zelle dann die Klasse class="red" verpassen.

    Klassen sollten nicht nach der gerade gewünschten Dastellung benannt werden. Richtig wäre eine Benennung wie class="negative".

    🖖 Live long and prosper

    --
    “Space: the final frontier. Above us. Around us. Within us.
    We have always looked to the stars to discover who we are.”

    — Michael Burnham in Star Trek: Discovery S2:E1
    1. problematische Seite

      @@Gunnar Bittersmann

      prüfen ob er mit einem Minuszeichen gefolgt von einer Zahl anfängt,

      Wenn du das schon einmal geprüft hast, musst du das nicht noch ein zweites Mal tun

      cell.textContent = cell.textContent.replace(/^-/, '\u2212');
      

      Du brauchst dann keinen RegExp, ein String tut’s auch:

      // ersetze Bindestriche durch Minuszeichen
      cell.textContent = cell.textContent.replace('-', '\u2212');
      

      🖖 Live long and prosper

      --
      “Space: the final frontier. Above us. Around us. Within us.
      We have always looked to the stars to discover who we are.”

      — Michael Burnham in Star Trek: Discovery S2:E1
    2. problematische Seite

      prüfen ob er mit einem Minuszeichen gefolgt von einer Zahl anfängt,

      Das ist bei dir nirgends der Fall. ‚-‘ (U+002D) ist kein Minuszeichen (außer in Computersprachen); ‚−‘ (U+2212) ist eins.

      Das kannste in deiner Schleife gleich mit berichtigen:

      // ersetze Bindestriche durch Minuszeichen
      cell.textContent = cell.textContent.replace(/^-/, '\u2212');
      

      Die Daten kommen aus einer LibreOffice-Calc-Tabelle. Wenn ich sie getippt hätte, wäre da aber auch ein ‚-‘ (U+002D). Mir ist es ziemlich egal weche Form von Viertelgeviertstrich da steht. Aber wenn sonst alles funktioniert, ändere ich auch das, wenn es wenig Aufwand ist. Die User mit deaktiviertem JavaScript müssen dann aber mit dem falschen Minuszeichen leben. Das Html kommt weiter per c&p aus Calc über https://tableconvert.com/de/excel-to-html nach Bluefish.

      und der Zelle dann die Klasse class="red" verpassen.

      Klassen sollten nicht nach der gerade gewünschten Dastellung benannt werden. Richtig wäre eine Benennung wie class="negative".

      Da sehe ich keinen Vorteil. Da kommen auch noch Zellen mit gelbem, rotem oder grünem Hintergrund und den Klassen bgYe, bgRd und bgGn. Was diese Farben bedeutet, wird in der Seite dann beschrieben. Diese Beschreibung mache ich sicher nicht in den Klassenamen zumal das mehere verschiedene Gründe haben kann.

      1. problematische Seite

        @@Friedel

        Mir ist es ziemlich egal weche Form von Viertelgeviertstrich da steht.

        Ein Minuszeichen ist aber eher ein Halbgeviertstrich. Aber nicht ganz; es sitzt auf der Höhe des waagerechten Balkens des Pluszeichens.

        Mir ist das nicht egal; ein Bindestrich statt Minuszeichen beißt bei mir im Auge.

        Aber wenn sonst alles funktioniert, ändere ich auch das, wenn es wenig Aufwand ist.

        Ist es. Den Einzeiler hab ich dir ja schon genannt. Der kommt genau dorthin, wo du auch die Klasse für die Zelle setzt. (cell könnte bei dir anders heißen.)

        Und damit es auch für die Geräte der Nutzer wenig Aufwand ist, wie gesagt nicht mit RegExp.

        Apropos Aufwand für die Geräte der Nutzer: Warum soll das Ganze dort laufen anstatt auf deinem Server? Wie generierst du aus deinen LibreOffice-Calc-Daten das HTML? Ein PHP-Script? Dann sollte die Erkennung negativer Werte auch dort laufen.

        🖖 Live long and prosper

        --
        “Space: the final frontier. Above us. Around us. Within us.
        We have always looked to the stars to discover who we are.”

        — Michael Burnham in Star Trek: Discovery S2:E1
        1. problematische Seite

          Hallo Gunnar,

          Wie generierst du aus deinen LibreOffice-Calc-Daten das HTML?

          Ja, diese Frage ist sehr entscheidend. Man sollte die gewünschten Manipulationen im Toolstack durchführen und nicht bei de[rm] EndbenutzerIn. Vor allem angesichts der Tatsache, dass es offenbar Benutzer gibt, bei denen JavaScript nicht ausgeführt wird.

          Rolf

          --
          sumpsi - posui - obstruxi
      2. problematische Seite

        @@Friedel

        Klassen sollten nicht nach der gerade gewünschten Dastellung benannt werden. Richtig wäre eine Benennung wie class="negative".

        Da sehe ich keinen Vorteil. Da kommen auch noch Zellen mit gelbem, rotem oder grünem Hintergrund und den Klassen bgYe, bgRd und bgGn.

        Warum so kryptisch? Die Klassen sollten wenn schon, dann backgroundYellow, backgroundRed bzw. backgroundGreen heißen, oder zumindest bgYellow, bgRed bzw. bgGreen.

        Was diese Farben bedeutet, wird in der Seite dann beschrieben. Diese Beschreibung mache ich sicher nicht in den Klassenamen zumal das mehere verschiedene Gründe haben kann.

        Oh, gerade dann!

        Du hast bspw. in deiner Tabelle folgende Zellen:

        <td class="bgYe">aus Grund 1</td>
        <td class="bgYe">aus Grund 2</td>
        <td class="bgRd">aus Grund 3</td>
        

        und im Stylesheet

        .bgYe { background: lightyellow }
        .bgRd { background: lightred }
        

        Jetzt fällt dir ein, dass für Grund 2 doch roter Hintergrund besser wäre. Wie machst du das? Vermutlich gar nicht, weil es hohen Aufwand bedeutet, die Zellen der Klasse bgYe durchzugehen und einige davon umzuklassifizieren.

        Weitaus besser ist es, die Unterscheidung von vornherein zu machen:

        <td class="grund1">aus Grund 1</td>
        <td class="grund2">aus Grund 2</td>
        <td class="grund3">aus Grund 3</td>
        

        mit

        .grund1, .grund2 { background: lightyellow }
        .grund3 { background: lightred }
        

        Dann ist ein Leichtes, das zu ändern in

        .grund1 { background: lightyellow }
        .grund2, .grund3 { background: lightred }
        

        🖖 Live long and prosper

        --
        “Space: the final frontier. Above us. Around us. Within us.
        We have always looked to the stars to discover who we are.”

        — Michael Burnham in Star Trek: Discovery S2:E1
  4. problematische Seite

    Hallo,

    Problem noch offen? Dann probiere mal diese kassenbuch.js

    window.addEventListener('DOMContentLoaded', function () {
      const zellen = document.querySelectorAll( "td" );
      for ( let i=0; i < zellen.length; i++ ) {
        if ( zellen[i].innerHTML.substring(0,1) == "-"
        &&   zellen[i].innerHTML.substring(1,2) >= "0"
        &&   zellen[i].innerHTML.substring(1,2) <= "9" ) {
          zellen[i].classList.add("red");
        }
      }
    });
    

    Gruß, Linuchs

    1. problematische Seite

      @@Linuchs

        for ( let i=0; i < zellen.length; i++ ) {
      

      Dass dies Unsinn ist, hatte ich dir unlängst schon gesagt. Und auch in diesem Thread nochmal verlinkt.

      🖖 Live long and prosper

      --
      “Space: the final frontier. Above us. Around us. Within us.
      We have always looked to the stars to discover who we are.”

      — Michael Burnham in Star Trek: Discovery S2:E1
      1. problematische Seite

        Hallo Gunnar,

        Dass dies Unsinn ist, ...

        Ich greife Anregungen gerne auf, aber manchmal ist man schneller mit (alten) gewohnten Techniken.

        Hier habe ich zum Testen die lfd. Variable gebraucht und als es denn funktionierte, den Code nicht noch mal auf Zustimmung der Gemeinschaft geändert mit notwendigen neuen Testläufen.

        Gruß, Linuchs

        1. problematische Seite

          @@Linuchs

          Ich greife Anregungen gerne auf

          In deiner Version von „gerne“‽

          aber manchmal ist man schneller mit (alten) gewohnten Techniken.

          Das mag sein, aber du musst dein veraltetes Wissen nicht noch unter die Leute bringen.

          🖖 Live long and prosper

          --
          “Space: the final frontier. Above us. Around us. Within us.
          We have always looked to the stars to discover who we are.”

          — Michael Burnham in Star Trek: Discovery S2:E1