Marco von Frieling: Problem mit Tabellen und Spaltenbreiten

Hallo.

Ich habe eine Tabelle mit mehreren Dutzend Spalten, die Tabelle ist also sehr viel breiter als das Browserfenster. Deshlab möchte, dass der Benutzer durch Klicken auf eine Spaltenüberschrift (th) die Spalte (col)  zugeklappt und solche Spalten wieder aufgeklappt werden.

Dies habe ich dadurch realisiert, dass jedem <th> für onClick eine Funktion mit dem Parameter event aufgerufen wird. Die Funktion hangelt sich dann durch den DOM hoch bis zum <table>-Element und sucht dann nach einem <col> mit dem gleichen Index wie das <th>. Für dieses <col> wird dann die Breite in eine andere Eigenschaft des Elements geschrieben (title ist sicher nicht optimal, sollte aber beim <col> nichts machen.), um sie wiederherstellen zu können. Dann wird die Breite auf 10px gesetzt.

Hier das Skript und die Tabelle:
<script type="text/javascript">

var ns6=document.getElementById&&!document.all;
  var ie=document.all;

function  switchColumn(e) {
    // Browserweiche, um das auslösende Element zu bekommen
    source=ie? event.srcElement : e.target
    // Spalte sichern, da source überschrieben wird
    index = source.cellIndex;
    // Im DOM nach oben gehen bis zur Tabelle ...
    while(source.nodeName!="TABLE")
      source=ns6? source.parentNode : source.parentElement;
    nodes = source.childNodes;
    // ... und dann die richtige Spalte suchen
    for (i = 0; i < nodes.length; i++) {
      if (nodes[i].nodeName == "COLGROUP") {
        nodes = nodes[i].childNodes;
        source = nodes[i];
        break;
      }
    }
    source = nodes[index];
    // Sicherheitsabfrage. Wenn Spalte nicht gefunden, hier aus der Funktion aussteigen
    if (source.nodeName != "COL") {
      return;
    }
    // Prüfen, ob zu- oder aufgeklappt werden muss. Da die Breite der Spalte über <col width=""> definiert werden muss, im IE aber nur über die CSS-Breite geändert werden kann, ist letztere beim Ersten Anklicken der Spaltenüberschrift noch nicht gesetzt.
    if (source.style.width == "" || source.style.width > 10) {
      // Sichern der Breite zum Aufklappen.
      source.title = source.width;
      // Reduzieren der Breite auf 10px.
      source.style.width = "10";
    }
    else {
      // Wiederherstellen der Breite
      source.style.width = source.title;
    }
  }
</script>

<table border="1" cellpadding="0" cellspacing="0">
 <colgroup>
  <col width="300" style="width:100" id="left" onclick="alert('Hallo!');" />
  <col width="50" style="width:200" id="middle" onclick="alert('Hallo!');" />
  <col width="120" style="width:5" id="right" onclick="alert('Hallo!');" />
 </colgroup>
  <tr id="ignore">
    <th height="26" scope="col" onClick="switchColumn(event);">Links</th>
    <th scope="col" onClick="switchColumn(event);">Mitte</th>
    <th scope="col" onClick="switchColumn(event);">Rechts</th>
  </tr>
  <tr>
    <td height="21">1</td>
    <td>2</td>
    <td>3</td>
  </tr>
  <tr>
    <td height="21">1</td>
    <td>2</td>
    <td>3</td>
  </tr>
  <tr>
    <td height="21">1</td>
    <td>2</td>
    <td>3</td>
  </tr>
  <tr>
    <td height="21">1</td>
    <td>2</td>
    <td>3</td>
  </tr>
  <tr>
    <td height="21">1</td>
    <td>2</td>
    <td>3</td>
  </tr>
</table>

Das Problem ist nun, dass die Spalte mindestens so breit bleibt wie die Zelle mit dem größten Inhalt. Die CSS-Eigenschaft overflow:hidden funktioniert hier scheinbar nicht, weder im IE noch in Firefox. Gibt es da eine Lösung oder zumindest einen Ansatz.

Eine Alternative wäre, die Spalte in eine andere unsichtbare Tabelle zu verschieben und später wieder zurückverschieben. Das gefällt mir aber nicht, weil es auch relativ aufwendig (Code und Rendern) und auch unsicher ist.

Danke für jeden Hinweis.

Gruß Marco

  1. Hi,

    Dies habe ich dadurch realisiert, dass jedem <th> für onClick eine Funktion mit dem Parameter event aufgerufen wird. Die Funktion hangelt sich dann durch den DOM hoch bis zum <table>-Element und sucht dann nach einem <col> mit dem gleichen Index wie das <th>.

    Wieso so umständlich? Durchnumerierte IDs für die THs und dann die COLs über document.getElementsByTagname ansprechen sollte doch gehen.
    Und das:

    var ie=document.all;

    könntest Du auch einsparen.

    Das Problem ist nun, dass die Spalte mindestens so breit bleibt wie die Zelle mit dem größten Inhalt. Die CSS-Eigenschaft overflow:hidden funktioniert hier scheinbar nicht, weder im IE noch in Firefox.

    Schonmal display:none probiert?

    freundliche Grüße
    Ingo

    1. Schonmal display:none probiert?

      Ingo,
      Und wie klappst du dann die Spalten wieder auf?
      Gunnar

      --
      Good results come from experience; and experience comes from bad results.
      1. Hi,

        Und wie klappst du dann die Spalten wieder auf?

        na mit document.getElementsByTagName('col')[0].style.display='inline'"
        Alerdings fürchte ich, daß nicht alle Browser diese Zuweisungen auf das COL-Element unterstützen, so daß Du möglicherweise in einer Schleife alle TDs der betreffenden Spalte ansprechen müßtest.
        Immerhin sparst Du Dir die obskure Verwendung des title-Attributes..;-)

        freundliche Grüße
        Ingo

        1. Und wie klappst du dann die Spalten wieder auf?

          na mit document.getElementsByTagName('col')[0].style.display='inline'"

          Und wie soll der Nutzer das aufrufen?

          Die Spalten dürfen nicht ganz verschwinden, damit sie der Nutzer durch Click auf die Überschrift (10px breit) wieder aufklappen kann.

          Und ist col nicht ein Blockelement?

          Gunnar

          --
          Good results come from experience; and experience comes from bad results.
          1. Hi,

            Und wie soll der Nutzer das aufrufen?

            Die Spalten dürfen nicht ganz verschwinden, damit sie der Nutzer durch Click auf die Überschrift (10px breit) wieder aufklappen kann.

            Diese 10px würde ich in einer eigenen Spalte voransetzen.

            freundliche Grüße
            Ingo

        2. Hi und danke schon mal für die rege Diskussion.

          Das geht ja richtig flott, in den Nwesgroups wo ich sonst drin bin (.NET etc.) dauert das meistens länger. ;-)

          Nur leider helfen mir die Antworten bislang nicht sehr viel.

          »Wieso so umständlich? Durchnumerierte IDs für die THs und dann die COLs »über document.getElementsByTagname ansprechen sollte doch gehen.
          Hatte ich schon mal ein Beispiel zu gefunden. Ist allerdings nicht umsetzbar, weil das ganze (sprich die Tabelle) per ASP.NET und C# aus einer Datenbank generiert wird. Und ASP.NET hat nun mal die Angewohnheit, alles was es identifizieren muss, und das werden sicher auch einige Tabellenzellen sein, mit automatisch erzeugten IDs auzustatten. Um das zu verhindern, müssten diverse Render-Methoden überschrieben werden, was vom Aufwand her auch nicht zu unterschätzen ist. Außerdem werden einige der generierten IDs ja serverseitig gebraucht.

          »Und das:

          var ie=document.all;

          »könntest Du auch einsparen.
          Das stammt aus einem JavaScript, welches ich bei HotScripts oder so gefunden habe und Tabellenzellen oder Zeilen beim Drüberfahren hervorhebt. Und da sind die Browserweichen zwischen IE und Netscape notwendig. Ich habe das Togglen der Spalten dann in die Skriptdatei mit reingeschrieben und in meinem Posting nur die anderen Funktionen gelöscht, weil die ja nichts mit dem Problem zu tun haben.
          Die Variablen ie und ns6 werden ja so belegt, dass jeweils eine der beiden (je nachdem welchen der Browser man gerade verwendet), gesetzt ist, die Andere dann nicht.

          Und wie klappst du dann die Spalten wieder auf?
          na mit document.getElementsByTagName('col')[0].style.display='inline'"
          Alerdings fürchte ich, daß nicht alle Browser diese Zuweisungen auf das COL-Element unterstützen, so daß Du möglicherweise in einer Schleife alle TDs der betreffenden Spalte ansprechen müßtest.

          Also ich habe display = "none" erfolgreich mit Firefox und IE getestet, da die Spalten dann aber weg waren und ich noch mehr/andere Probleme hatte, konnte ich sie nicht wieder einblenden.

          Aber das bringt mich auf eine Idee:
          Bisher wurde das Toggeln serverseitig durchgeführt, was natürlich massiv Traffic und zahlreiche Postbacks verursacht. Jedenfalls gibt es jetzt einen nach unten zeigenden Pfeil zum zuklappen (am Anfang ist ja alles sichtbar), der an den Server sendet, welche Spalte getoggelt werden soll. Diese wird dann zugeklappt und gar nicht mit übertragen. Der Pfeil zeigt dann nach rechts. Beim Aufklappen werden die Zellen dann wieder mit gerendert.
          Es müsste dann ja möglich sein, links neben jeder Datenspalte eine zusätzliche Spalte zu definieren, die nur ein TH ohne rechten Rahmen und keine TDs enthält. Das TH enthält dann den Pfeil, der mit einem onClick verbunden ist. Dieses kann dann die Col entweder über den Index des TH-Elements oder über eine ID der Col aus- oder einblenden.

          Hier ist ein kurzes Beispiel (der Inhalt der Tabelle ist etwas blöd, aber darum geht es ja nicht):
          <table border="0" cellspacing="0" cellpadding="0">
           <colgroup>
            <col width="10"/>
            <col id="date"/>
            <col width="10" />
            <col id="ip" />
           </colgroup>
           <tr>
            <th class="togglehead" onclick="alert('Toggle Datum');">&gt;&nbsp;/th>
            <th>Datum</th>
            <th class="togglehead" onclick="alert('Toggle IP-Adresse');">&gt;&nbsp;</th>
            <th>IP-Adresse</th>
           </tr>
           <tr>
            <td class="togglecol"></td>
            <td>heute</td>
            <td class="togglecol"></td>
            <td>localhost</td>
           </tr>
           <tr>
            <td class="togglecol"></td>
            <td>gestern</td>
            <td class="togglecol"></td>
            <td>127.0.0.1</td>
           </tr>
          </table>

          Immerhin sparst Du Dir die obskure Verwendung des title-Attributes..;-)

          Ist zu empfehlen, wusste mir nur gerade nicht anders zu helfen. Was besseres, das von beiden Browsern unterstützt wird, konnte ich so schnell nicht finden.

          Schönen Abend noch.

          Marco

          1. Hi,

            »Wieso so umständlich? Durchnumerierte IDs für die THs und dann die COLs »über document.getElementsByTagname ansprechen sollte doch gehen.
            [...] Um das zu verhindern, müssten diverse Render-Methoden überschrieben werden, was vom Aufwand her auch nicht zu unterschätzen ist. Außerdem werden einige der generierten IDs ja serverseitig gebraucht.

            Tja, Deine Entscheidung, wo Du den Aufwand betreiben willst - serverseitig oder clientseitig. Der Client würde sicherlich einen, wenn auch kleinen, Nutzen haben, wenn der Server einen leichter zu verarbeitenen Code liefert.

            var ie=document.all;
            »könntest Du auch einsparen.
            Das stammt aus einem JavaScript, welches ich bei HotScripts oder so gefunden habe und Tabellenzellen oder Zeilen beim Drüberfahren hervorhebt. Und da sind die Browserweichen zwischen IE und Netscape notwendig.

            Nö, ist es nicht. Ein Relikt aus Zeiten, in denen der IE4 noch weiter verbreitet war.

            Bisher wurde das Toggeln serverseitig durchgeführt, was natürlich massiv Traffic und zahlreiche Postbacks verursacht.

            Ich war eigentlich davon ausgegangen, daß Du - wenn Du ja ohnehin schon Javascript dazu verwendest - das natürlich auch clientseitig machst; dazu ist Javascript doch da.

            freundliche Grüße
            Ingo

            1. Hallo Ingo.

              Ich war eigentlich davon ausgegangen, daß Du - wenn Du ja ohnehin schon Javascript dazu verwendest - das natürlich auch clientseitig machst; dazu ist Javascript doch da.

              Das habe ich nicht gemacht, das war schon da als ich in das Projekt eingebunden wurde. Da wurde das halt serverseitig gemacht, und als das Projekt immer weiter gewachsen ist und die ersten echten Kunden (zusätzlich zu den Testkunden) das Portal nutzen konnten, hat man sich wohl mal die Protokolle des Webservers angeschaut und gemerkt, dass diese Funktion sehr stark genutzt wird und somit viel Traffic verursacht. Deshalb wohl die Entscheidung, das clientseitig zu machen, weil das auch alles mit Kosten (für uns und den Kunden) verbunden ist.

              Und dann lass mal die Azubis machen, die können da wenigstens noch was bei lernen. Denn Einiges, was programmiertechnisch in der Firma noch nicht gemacht wurde, dürfen die Azubis lernen und dann weitervermitteln. (Was ich irgendwo auch gar nicht so schlecht finde.)

              Gruß Marco