Enrico: Wechsel von "display none" nach "display block" zerstört Tabellen-Layout

Hallo zusammen,

ich erzeuge über PHP folgende Tabelle:

<table>
   <thead>
      ...
   </thead>
   <tbody id="listeHeute">
      ...
   </tbody>
   <tbody id="listeZukuenftig">
      ...
   </tbody>
   <tbody id="listeVergangen">
      ...
   </tbody>
</table>

Die Tabelle führt einen eventuell heute anfallenden Auftritt von uns auf sowie zukünftige und vergangene Auftritte:

Ich möchte nun mittels JavaScript in Abhängigkeit vom angeklickten Textlink ("Heute", "Zukünftig" und "Vergangen") die jeweils nicht benötigten tbodies ausblenden lassen:

var kategorien = ["heute", "zukuenftig", "vergangen"];

var w,
    x = kategorien.length;

aufrufen (0);

function aufrufen (nr)
{
   w = 0;

   for (; w < x; w++)
   {
      document.getElementById("liste" + kategorien[w][0].toUpperCase() + kategorien[w].substring(1)).style.display = "none"
   }

   document.getElementById("liste" + kategorien[nr][0].toUpperCase() + kategorien[nr].substring(1)).style.display = "block";
}

Das Array "kategorien" wird ebenfalls über PHP erzeugt. Gibt es keinen heutigen Auftritt, so wird "kategorien" keinen Eintrag "heute" enthalten. Sind nur vergangene Auftritte vorhanden, dann wird "kategorien" nur den Eintrag "vergangen" enthalten usw. Deswegen durchlaufe ich das Array auch mit einer Schleife.

Ich verstecke zuerst alle tbodies aus ("display: none") und möchte nur den anzuzeigenden tbody sichtbar machen ("display: block").

Leider wird dabei aber der Tabellenaufbau zerstört:

Was mache ich falsch?

Vielen Dank für eure Hilfe und Gruß Enrico

akzeptierte Antworten

  1. Tach!

    Ich verstecke zuerst alle tbodies aus ("display: none") und möchte nur den anzuzeigenden tbody sichtbar machen ("display: block").

    Leider wird dabei aber der Tabellenaufbau zerstört:

    Was mache ich falsch?

    Schau mal in die Entwicklertools, welcher Wert für display bei einem tbody voreingestellt ist. Diese Voreinstellung bekommst du auch wieder, wenn du den Wert none nur entfernst statt einen unpassenden zu setzen.

    dedlfix.

    1. Hi dedlfix,

      perfekt! "table-row-group" anstatt "block" und schon klappt es.

      Da muss man erst mal darauf kommen 😀

      Danke und Gruß Enrico

      1. @@Enrico

        perfekt! "table-row-group" anstatt "block" und schon klappt es.

        Das war nicht das, was dedlfix dir sagen wollte, sondern "".

        Und damit hat dedlfix dich leider auf deinem Irrweg ein Stück vorangebracht.

        Der Fehler ist, überhaupt CSS-Eigenschaften direkt mit JavaScript zu ändern. Dazu gleich mehr.

        LLAP 🖖

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

    var w,
        x = kategorien.length;
    

    w brauchst du an der Stelle nicht, sondern nur in der Funktion aufrufen(). Die Variable sollte demzufolge in der Funktion lokal deklariert werden.

    function aufrufen (nr)
    {
       w = 0;
    
       for (; w < x; w++)
    

    Seltsame Schreibweise. Üblich ist

    function aufrufen(nr)
    {
    	for (var w = 0; w < x; w++)
    

    oder wenn du die Variable vorher deklarieren willst:

    function aufrufen(nr)
    {
    	var w;
    
    	for (w = 0; w < x; w++)
    

    In modernen Browsern mit dem Schlüsselwort let statt var.

          document.getElementById("liste" + kategorien[w][0].toUpperCase() + kategorien[w].substring(1))
    

    Kannst du deine IDs statt in CamelCase nicht mit Bindestrich benennen? <tbody id="liste-heute"> usw.? Dann kannst du dir den ganzen umständlichen Kram sparen und hast einfach

    		document.getElementById("liste-" + kategorien[w])
    

    Ich verstecke zuerst alle tbodies aus ("display: none") und möchte nur den anzuzeigenden tbody sichtbar machen ("display: block").

    Warum das denn? Durch die Schleife gehen und abfragen, ob der aktuelle Schleifenindex w gleich nr ist. Wenn ja, auf "block" setzen, andernfalls auf "" (siehe andere Antwort):

    function aufrufen(nr)
    {
    	for (var w = 0; w < x; w++)
    	{
    		if (w == nr)
    		{
    			document.getElementById("liste-" + kategorien[w]).style.display = "block";
    		}
    		else
    		{
    			document.getElementById("liste-" + kategorien[w]).style.display = "";
    		}
    	}
    }
    

    oder kurz

    function aufrufen(nr)
    {
    	for (var w = 0; w < x; w++)
    	{
    		document.getElementById("liste-" + kategorien[w]).style.display = (w == nr) ? "block" : "";
    	}
    }
    

    Was mache ich falsch?

    .style.display = "none"
    

    Ich krame mal wieder den Cheatah raus:
    „Was hingegen schwer ist, ist in die Köpfe der Menschen zu bringen, dass Layout-Informationen in den CSS-Code gehören, nicht in den JavaScript-Code. JavaScript ist wunderbar geeignet, die DOM-Objekte auf eine Weise zu verändern, die in CSS genutzt werden kann.“

    Nun könnte jemand sagen: Das Anzeigen/Nicht-Anzeigen wäre keine „Layout-Information“. Dann hat das erst recht nichts im style-Objekt zu suchen.

    Zum Nicht-Anzeigen gibt es das HTML-Attribut hidden. Dieses ist hier zu verwenden:

    function aufrufen(nr)
    {
    	for (var w = 0; w < x; w++)
    	{
    		if (w == nr)
    		{
    			document.getElementById("liste-" + kategorien[w]).removeAttribute("hidden");
    		}
    		else
    		{
    			document.getElementById("liste-" + kategorien[w]).setAttribute("hidden", "");
    		}
    	}
    }
    

    Dann wäre das Problem mit dem flaschen Wert für die display-Eigenschaft gar nicht erst aufgetaucht.

    LLAP 🖖

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

      Zum Nicht-Anzeigen gibt es das HTML-Attribut hidden. Dieses ist hier zu verwenden:

      function aufrufen(nr)
      {
      	for (var w = 0; w < x; w++)
      	{
      		if (w == nr)
      		{
      			document.getElementById("liste-" + kategorien[w]).removeAttribute("hidden");
      		}
      		else
      		{
      			document.getElementById("liste-" + kategorien[w]).setAttribute("hidden", "");
      		}
      	}
      }
      

      Es sollte auch so gehen:

      function aufrufen(nr)
      {
      	for (var w = 0; w < x; w++)
      	{
      		if (w == nr)
      		{
      			document.getElementById("liste-" + kategorien[w]).hidden = false;
      		}
      		else
      		{
      			document.getElementById("liste-" + kategorien[w]).hidden = true;
      		}
      	}
      }
      

      Was sich dann kurz schreiben lässt:

      function aufrufen(nr)
      {
      	for (var w = 0; w < x; w++)
      	{
      		document.getElementById("liste-" + kategorien[w]).hidden = (w != nr);
      	}
      }
      

      IIRC haben einige ältere Browser (IE < ?) Probleme mit .hidden; da funktioniert’s nur mit setAttribute()/removeAttribute().

      LLAP 🖖

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

        ich bin platt! Super Antwort! Und danke, dass Du mich auf den Irrweg hingewiesen hast!

        Gruß Enrico