Präsentation von Tabellen mit CSS

Das <z:table>-Tag ist eine Art Bindeglied zwischen der ABAP-Welt und der Webanwendung. Es hilft, tabellenförmige Daten zu präsentieren. Die Implementierung ist dabei so flexibel, dass Sie praktisch alle besonderen Präsentations- und Layoutvorgaben in Ihrem Projekt modifikationsfrei hinzufügen können. In diesem Artikel will ich Ihnen zunächst die Möglichkeiten zeigen, mit CSS-Mitteln und wenigen steuernden Angaben im <z:table>-Tag die Präsentation zu verändern. Schauen Sie sich auch die Taglib-Demoanwendung auf unserem Entwicklungssystem an, um weitere Anwendungsbeispiele des <z:table>-Tags kennenzulernen.

Ein einfaches Beispiel

Im einfachsten Fall übergeben Sie dem <z:table>-Tag lediglich eine ABAP-Tabelle oder eine Referenz auf eine solche Tabelle in Form eines Datenbindungsausdrucks. Die Tabelle muss eine Indextabelle sein, also sortiert oder Standard. Hashtabellen sind nicht darstellbar.

Hier das Einfachstbeispiel aus unserer Taglib-Demo-Anwendung. Es weist das <z:table>-Tag an, die interne Tabelle gt_test des Models mit der ID test darzustellen.

  <z:table binding="//test/gt_test"/>
gt_test, die darzustellende Tabelle, enthält Nachrichten. Die Zeilenstruktur enthält in diesem Beispiel die textförmigen Komponenten Die obige Anweisung im View generiert den folgenden HTML-Code. Beachten Sie, dass die Überschriften automatisch aus den Datentypen der Komponenten ermittelt wurden (natürlich können Sie die Generierung der Überschriftzeile ganz abschalten oder einzelne Spalten mit Hilfe des inneren <z:column>-Tags mit anderen Texten versehen). Die Zellinhalte werden dagegen aus den Inhalten der entsprechenden Tabellenfelder genommen. Mit Mechanismen wie Substitution bzw. Table Exits können diese Inhalte modifikationsfrei verändert werden.
<table id="M__test__gt_test" class="listcontainer">
  <tr>
    <td class="listheader" >Sprache</td>
    <td class="listheader" >Arbeitsgebiet</td>
    <td class="listheader" >Nachricht</td>
    <td class="listheader" >Nachrichtentext</td>
    <td class="listheader" >Nachrichtenart</td>
  </tr>
  <tr id="M__test__gt_testRow0001" class="zebra2">
    <td>DE</td>
    <td>AH</td>
    <td>674</td>
    <td>Operand &1 darf in den Anlagefakten nicht gepflegt werden</td>
    <td>I</td>
  </tr>
  <tr id="M__test__gt_testRow0002" class="zebra1">
    <td>DE</td>
    ...
  </tr>
  ...
</table>
Und so sieht die Tabelle im Browser aus:

Trennung von Daten und Präsentierung

Beachten Sie in dem obigen Quellcode zunächst, dass der gerenderte HTML-Code nur die reine Tabellenstruktur enthält - keine Präsentierungsinformationen. Es wird, wie es der CSS-Philosophie entspricht, alles in Stylesheetklassen ausgelagert, was die Präsentation der Tabelle betrifft. Der generierte HTML-Code enthält dagegen nur das Tabellen-Template, wie es durch die im <table>-Element enthaltenen <td>- und <tr>-Elemente gegeben ist, dazu die Überschriften und die Daten. Das gesamte, vom <table>-Element aufgespannte HTML-Fragment ist übrigens nach XML-Syntax wohlgeformt, so dass sich das <z:table>-Element auch in XHTML-Seiten einsetzen lässt. (Wir nutzen diese Wohlgeformtheit übrigens auch in den Unit Tests der Elementbehandlerklasse zcl_bsp_z_table: Ein XML-Dokument kann in ABAP sehr bequem mit den iXML-Klassen untersucht werden, während mir ein HTML-Parser in ABAP nicht bekannt ist).

In der Datei ../public/mvc/global.css finden Sie den folgenden Präsentierungsvorschlag (den "Standard" — hier habe ich den CSS-Code um einige Kommentare ergänzt):

/* Tabellen: 
   Rahmenmodell "Kollabierende Zellrahmen"
   Rechts und unten etwas dickere graue Rahmenlinie (Schatteneffekt) 
   */
.listcontainer { border-collapse:collapse;
                 border-right: solid 2px #999;
		 border-bottom: solid 2px #999; 
                 }
		 
/* Einzelne Zellen von Tabellen der Klasse listcontainer:
   Etwas dunklere, feine Linien (1 Pixel)
   2 Pixel Innenabstand
*/ 
.listcontainer td { border:solid 1px #666666;
                    padding: 2px;
                    }		 
/* Überschriften sind normale <td>-Elemente (nicht <th>) der Klasse listheader
   Blauer Hintergrund
   Schrift hervorgehoben
*/
.listheader { background-color: #B4B4FF;
              font-weight: bold
	      }

/* Zebramuster */
.zebra1		{ background-color: #DDD }
.zebra2		{ background-color: white }
Dies ist wirklich nicht mehr als ein Präsentierungsvorschlag. Es ist genau die Präsentierung, wie sie im Retail Store der Migros benötigt wird. Aber nichts daran ist heilig. Sie können alles ändern - Hintergrundfarbe, Rahmenmodell, Schriften, Positionierungen, Innen- und Aussenabstände, kurz alles, was überhaupt mit CSS änderbar ist. Sie kaskadieren in Ihren Webanwendungen diese Stylesheetangaben, indem Sie Ihre Angaben in einem eigenen, zentralen CSS-Dokument machen.

Einzelne Tabellen ansprechen

Wie Sie weiter sehen, hat die Tabelle automatisch eine ID bekommen. Die ID ist ein aus dem Datenbindungsausdruck abgeleiteter HTML-Name. Sie können die ID jedoch durch einen eigenen Wert überschreiben:
<z:table table_id="meineTabelle" binding="//test/gt_test"/>
Die ID können Sie verwenden, um eine bestimmte Tabelle mit CSS-Angaben anzusprechen und damit auf eine individuelle Weise zu präsentieren. Ein Beispiel: Wenn Sie die Tabelle wie folgt im View deklarieren:
  <z:table table_id="meineTabelle" 
           binding="//test/gt_test" 
           zebra=" "/>
und darüberhinaus mittels CSS festlegen, dass die Table Rows gelben Hintergrund bekommen sollen:
/* Meine Tabelle mit gelbem Hintergrund darstellen */
<style type="text/css">
  table#meineTabelle tr { background-color: yellow; }
</style>
so erhalten Sie die folgende Darstellung. Beachten Sie, dass die Überschriftszeile trotzdem noch blau dargestellt wird, da sie eine class-Angabe enthält (die im globalen Stylesheet global.css definiert wird).

Vor allem ist eine kurze, selbstdefinierte ID jedoch nützlich, um Elemente des HTML-DOMs mit JavaScript anzusprechen. Vor allem aus diesem letzteren Grund bekommen auch alle Tabellenzeile eine ID, die wie folgt gebildet wird:

  rowID := tableID + "Row" + tableIndex
Dabei ist tableID die ID der gesamten Tabelle und tableIndex der Index der dargestellten Zeile in der internen Tabelle. Wegen des variablen tableIndex ist die Zeilen-ID für CSS-Angaben meist wohl nicht nützlich. Sie könnten bestimmte Zeilen auf besondere Weisen präsentieren, wie hier:
<style type="text/css">
  tr#meineTabelleRow0002 { background-color: yellow; }
</style>
ergibt folgende Präsentierung:

Einzelne Zeilen ansprechen

Für Scripting ist es besser, Elemente mit griffigen ID's statt mit exakten Datenbindungsausdrücken anzusprechen. Dafür sind die obigen ID's der Tabellenzeilen ideal geeignet. Sie können bequem in einer Schleife alle sichtbaren Tabellenzeilen durchlaufen, oder aus der ID einer Zelle den Tabellen-Index der internen Tabelle in der ABAP-Welt ermitteln.

Natürlich können Sie auch mittels Scripting eine bestimmte Tabellenzeile hervorheben. Die folgende Funktion hebt die Zeile mit Tabellenindex idx hervor, indem sie ihr die Klasse focus gibt:

  function setFocus(idx) {
    setClass(byId("meineTabelleRow"+substring(10000+idx,1)),"focus");
    }

Zebramuster ausschalten

Normalerweise unterstützt ein Zebramuster die Lesbarkeit einer Tabelle. Sie können es jedoch abschalten, indem Sie das Boolesche Attribut zebra im <z:table>-Tag auf " " setzen.
<z:table zebra=" " binding="//test/gt_test"/>
Wenn das umgebende Dokument keine Hintergrundfarbe hat, hat die Tabelle dann folgendes Erscheinungsbild:

Wenn Sie - wie oben - den Tabellenzeilen einen eigenen Stil geben wollen, können Sie dies durch Ausschalten des Zebra-Stils und Angabe einer CSS-Regel für <tr> tun. Sie können aber auch die Selektoren .zebra1 und .zebra2 in einem eigenen Stylesheet überschreiben, das nach global.css eingelesen wird:

<style type="text/css">
  .zebra1, .zebra2 { background-color: yellow; }
</style>

Einzelne Spalten ansprechen

Sie können auch Spalten eine Stylesheet-Klasse geben. Hierfür verwenden Sie das Attribut tdClass des Spalten-Definitionselements <z:column> wie hier:
  <z:table table_id="meineTabelle" 
           binding="//test/gt_test" 
           zebra=" ">
    <z:column name="msgnr" tdClass="msgnr">
  <z:table>
Mit der Syntax für CSS-Selektoren haben Sie nun die Möglichkeit, Zeilen oder Spalten oder durch Kombination der beiden Ausdrücke sogar einzelne Zellen (als Schnittpunkte einer Zeile und einer Spalte) zu formatieren:
<style type="text/css">
  #meineTabelleRow0002        { background-color: yellow; }
  .msgnr                      { background-color: red;    }
  #meineTabelleRow0002 .msgnr { background-color: orange; }
</style>
ergibt zum Beispiel das folgende Bild:

Zurück