Artikel - Detailansicht

Icon Aktuelles Dynamische Listboxen mit WDDX

Nach all der Theorie über WDDX soll nun in diesem Artikel ein praktisches Beispiel folgen.
Dazu wollen wir zwei Selectboxen dynamisch mit Werten aus einem Datenbank-Query füllen, wobei eine Auswahl in der ersten Selectbox eine Änderung der 2. Selectbox zur Folge hat.
Dieser Technik eröffnet dem aufstrebenden Webentwickler einige interessante Möglichkeiten für die Bedienung von Webapplikationen. Man kann z.B. in der ersten Selectbox mehrere Sprachen zur Auswahl stellen und bei Selektion in der 2. Selectbox ein Auswahlmenü in der entsprechenden Sprache erzeugen, oder in der ersten Box wählt man in einem Shopsystem die Produktgruppe und in der 2. Selectbox das Produkt.

In einer normalen Applikation würde die Selektion eines Elementes in der ersten Selectbox normalerweise eine Datenbankabfrage mit dem ausgewählten Element als Parameter nachsich ziehen um mit dem Ergebnis dann die 2. Selectbox zu füllen. Man könnte dieses Verhalten natürlich auch simulieren indem man nach der ersten Selektion zu einer 2. Seite weiterschalten und dort die Datenbankabfrage durchführt. Jeder kann sich sicherlich denken, dass das nicht gerade sehr schnell und komfortabel ist.
Mit etwas Javascript, ColdFusion und WDDX kann man dieses dynamische Selectbox-Set viel userfreundlicher erzeugen. Es reagiert ohne merkliche Verzögerung auf Usereingaben und läuft auch Offline.

Fangen wir also an. Ziel soll es sein, 2 Selectboxen zu erzeugen, wobei die 1. eine Liste von Autohersteller enthält und die 2. Selectbox eine Auswahl von Autotypen, die vom jeweiligen selektierten Hersteller abhängt. Als Basis unserer Daten ist eine Datenbank mit der Tabelle autos und den Spalten hersteller und typ vorhanden. Im Beispielscript wird folgender Tabelleninhalt benutzt:

hersteller typ
Fiat Croma
Fiat Panda
Fiat Punto
Fiat Uno
Opel Corsa
Opel Kadett
Opel Omega
VW Golf
VW Passat
VW Polo
VW Vento

Das daraus resultierende Ergebnis sieht dann so aus (das Textinput-Element dient nur zur Anzeige des gewählten Eintrags) und wird in wenigen Minuten jedem in der Funktion klar sein :-):


Die folgenden Schritte sind notwendig:

  • Ausführen einer Datenbankabfrage um an die Daten für die Selectboxen zu gelangen
  • Umwandeln des ColdFusion-Queryset in Javascriptvariablen
  • Mittels Javascript die Selectboxen entsprechend füllen und auf Eingaben reagieren

Schritt 1
Wir führen eine normale Datenbankabfrage durch. Dieser Code wird auf dem Server von ColdFusion ausgeführt!

<cfquery name="autos" datasource="myDSN">
  select hersteller,typ from autos
</cfquery>

Schritt 2
Nun muß das Queryset autos nach Javascript konvertiert werden. Dazu benutzen wir das schon beschriebene ColdFusion-Tag CFWDDX (die JS-Script-Tags nicht vergessen, denn es wird Javascripcode durch CFWDDX erzeugt!):

<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript">
   <cfwddx action="cfml2js" input="#autos#"
   toplevelvariable="js_autos">
</SCRIPT>


Das Ergebnis dieser Zeilen ist ein WddxRecordset-Objekt mit dem Namen js_autos, dessen Elemente der des ColdFusion-Querysets autos entsprechen.
Die Struktur und Methoden des WddxRecordsets sind in der Javascriptlibrary Wddx.js definiert, die man mit diesen Zeilen in die Seite einbinden muss:

<script SRC="/cfide/scripts/wddx.js"></script>

Das SRC-Attribut muss mit dem Pfad zu diesem Script gesetzt werden. Man kann die Datei wddx.js aber auch in ein beliebiges zur Site gehörendes Verzeichnis kopieren und den Pfad entsprechend anpassen.

Nach dem Konvertieren sind noch einige Vorbereitungsarbeiten mit Javascript nötig. Zuerst werden die benötigten globalen Javascript-Variablen angelegt. Die wichtigen davon sind:

autoArray=new Array();
box1=null;
box2=null;

Die Variablen box1 und box2 werden später die Referenz auf die beiden Selectboxen aufnehmen. Die Variable autoArray soll die Query-Daten als zweidimensionales Array aufnehmen. Da man in Javascript nicht direkt mehrdimensionale Arrays erzeugen kann gehen wir hier einen Umweg, indem zuerst ein einfaches Array erzeugt wird, dessen Elemente dann wiederum Arrays werden. Das Ziel ist ein zweidimensionales Array, dessen Zeilen jeweils einen Eintrag eines Herstellers inkl. Typen erhalten. In der ersten Spalte stehen dann die Hersteller und in den folgenden Spalten die zugehörigne Typen:

Fiat Croma Panda Punto Uno
Opel Corsa Kadett Omega
VW Golf Passat Polo Vento

Diese etwas komplizierte Struktur ermöglich aber einen sehrt einfachen und schnellen Zugriff auf die Typen eines Herstellers, denn man muss nur bei gegebenen Hersteller den Index der entsprechende Zeile finden und kann dann alle Werte der Zeile bequem über den ermittelten Index ansprechen.
Fiat befindet sich also auf dem Feld autoArray[0][0], Opel auf autoArray[1][0] usw. Alle Typen von Opel lassen sich also über autoArray[1][x] auslesen.
Man muss nicht unbedingt dieses Prinzip anwenden um dynamische Selectboxen zu erzeugen. Es bleibt jeden selbst überlassen, die für seine Zwecke am besten geeignetste Datenstruktur zu finden.

Das Array js_autos wird gleich beim Laden der Webseite aus dem WddxRecordset mit diesem Code erstellt:

for (var i=0; i<js_autos.getRowCount(); i++) {
  if (last == js_autos.hersteller[i]) {
    //zeile fuellen
    autoArray[rowIdx][colIdx]=js_autos.typ[i];
    colIdx++;
  }
  else {
    //neue zeile anlegen    
    rowIdx++;
    autoArray[rowIdx]=new Array();//neues Array fuer typen erzeugen
    colIdx=2;
    autoArray[rowIdx][0]=js_autos.hersteller[i];//1.spalte=hersteller
    autoArray[rowIdx][1]=js_autos.typ[i];
    last=js_autos.hersteller[i];
  }
}


getRowCount() ist eine Methode (definiert in der Datei wddx.js) des WddxRecordsets, mit dem wir die Anzahl der Recordset-Zeilen ermitteln können (ähnlich Query.Recordcount in CF).

Beim Ansprechen der Spalten eines WddxRecordsets muss man beachten dass Tabellenspalten des Querysets in lowercase umgewandelt werden. Würde also die Originalspalte der Datenbank Hersteller oder herSteller lauten, wäre der Spaltenname imWddxRecordset in beiden Fällen hersteller und nur über js_autos.hersteller[i] ansprechbar. Der Ausdruck js_autos.Hersteller[i] würde einen Fehler auslösen.

Schritt 3
Wir haben jetzt die Daten in Javascript (autoArray[][] )verfügbar. Nun müssen die Selectboxen gefüllt werden. Dazu erzeugen wir zuerst die Selectboxen im HTML-Code:

  

<form NAME="f1">
  <select name="hersteller" size="5"
    onChange="hersteller_onChange()">
    <OPTION VALUE="1">=====(loading)=====</OPTION>
  </select>
  <select name="typ" size="5" onChange="typ_onChange()">
    <OPTION VALUE="1">=====(loading)=====</OPTION>
  </select>
  <br>
  <input type="text" name="auswahl">
</form>

Die OPTION-Elemente müssen mit einem Wert vorbelegt werden, der für den Browser die Breite der Selectbox beim Laden der Seite angibt. Nötig ist das allerding nur für den Netscape-Browser, der Internet Explorer passt die Breite der Selectboxen dynamisch den darzustellenden Inhalten an.
Jeder Selectbox wird eine Javascript-Funktion als Eventhandler zugeordnet, die aufgerufen wird, wenn sich der Selektionszustand ändert. Wichtig ist dabei der Eventhandler der ersten Selectbox, denn in dieser Funktion müssen wir in Abhängigkeit der Auswahl die 2. Box füllen.
Die Boxen müssen beim Aufruf der Seite natürlich zuerst einmal mit Daten gefüllt werden. Wir setzen dazu in das Body-Tag der Seite einen onLoad-Eventhandler (wird aufgerufen, wenn die Seite vollständig geladen wurde).

  

<body onLoad="init()">

Der zur init()-Funktion gehörende Code sieht in diesem Beispiel so aus:

function init(){
  box1=document.f1.hersteller;
      //referenzen speichern
box2=document.f1.typ;        
  box1.options.length=0;
            //selectboxen loeschen
  box2.options.length=0;
  for (i=0; i<autoArray.length; i++) {
    //neuen eintrag in selectbox anlegen
    box1.options[box1.options.length]=new Option(autoArray[i][0],autoArray[i][0]);
  }                
  box1.selectedIndex=0;
             //1. eintrag selecktieren  
hersteller_onChange();  
}


Zuerst werden die Referenzen der beiden Selectboxen zur Einsparung von Schreibarbeit in den globalen Variablen box1 und box2 gespeichert.
Dann wird die Selectbox gelöscht, indem man die Länge des Option-Objekt-Arrays auf Null setzt.

Um den Javascriptcode besser verstehen zu können, sollte man wissen, dass die Selectbox- und Option-Objekte sich in einigen Punkten von anderen Formularelementen unterscheiden. Das Option-Objekt ist z.B. selbst kein Formularelement, sondern ein Objekt, das Teil des Select-Objektes (Selectbox) ist. Das Select-Objekt ist das einzige Formularelement, das andere Objekte enthält. Diese Objekte werden in dem Array options[] gespeichert und lassen sich manipulieren wie ganz normale Array-Elemente.
Das Besondere an den Option-Objekten ist, dass wir sie zur Laufzeit (ab NS3.0) durch den Konstruktor Option() dynamisch erzeugen und dem Array options[] zuweisen können (dadurch erscheinen sie in der Selectbox). Durch Setzen der Eigenschaft length des Arrays options[] löschen wir alle Eingträge. Aber auch Anhängen von neuen Eingrägen ist problemlos über das options[]-Array möglich.
Das versetzt uns erst in die Lage, die Werte der 2. Selectbox dynamisch auszutauschen.
Zur Initzialisierung loopen wir durch autoArray und lesen die erste Spalte (i=0) und damit die Werte der Hersteller aus. Wir erzeugen dann jeweils ein Option-Objekt.
Am Schluss selektieren wir den ersten Eintrag der 1. Selectbox, indem wir deren Eigenschaft selectedIndex auf Null setzen. Soll kein Eintrag vorselektiert werden, kann man diese Zeile auch weglassen bzw. explizit auf -1 setzen.
Um jetzt auch die 2. Selectbox vorzufüllen, rufen wir einfach den Eventhandler der 2. Selectbox direkt auf (schliesslich ist in der 1. Box der erste Eintrag ausgewählt).

Jetzt müssen nur noch die zu den Selectboxen gehörenden Eventhandler geschrieben werden, die die Einträge der Selectboxen auswerten können:

function hersteller_onChange(){
  for (i=0; i<autoArray.length; i++) {  
    if (box1.options[box1.selectedIndex].value==autoArray[i][0]){
      index=i;
      break;
    }
  }
  box2.options.length=0;
  for (i=1; i<autoArray[index].length; i++) {    
    if (autoArray[index][i] !=null)          
      box2.options[box2.options.length]=new
                  Option(autoArray[index][i],autoArray[index][i]);
    }
    box2.selectedIndex=0;
    typ_onChange();
  }
}          
    
function typ_onChange(){
  document.f1.auswahl.value=box2.options[box2.selectedIndex].value;
}          

Der Eventhandler der 1. Selectbox muss den selektierten Eintrag ermitteln. Mit dem Ausdruck box1.selectedIndex erhält man den Index des selektierten Option-Objekts innerhalb des Select-Objekts (Selectbox). Damit kann man dann über box1.options[box1.selectedIndex].value den selektierten Wert (Hersteller als String) ermitteln.
Mit diesem Wert wird in der 1. for-Schleife der Index der Typen des Herstellers ermittelt (Loop über autoArray). Ist dieser gefunden kann in einer 2. for-Schleife die 2. Selectbox mit den zum Hersteller gehörigen Typen gefüllt werden. Dabei wird aber mit autoArray[index][i] !=null vor jedem Anlegen eines neuen Options-Objektes geprüft, ob auch ein Wert in autoArray vorhanden ist. Dadurch sind wir bei dem Array nicht darauf angewiesen, das alle Obereinträge (Hersteller) die gleiche Anzahl Untereinträge (Typ) haben.
Zuletzt wird der erste Eintrag der Typen-Selectbox gesetzt und der Eventhandler für die Typen-Selectbox aufgerufen. Der schreibt zum Test den Endwert in die Eingabebox.

Der komplette Code kann hier downgeloadet werden.



Steffen Goldfuss steffen@goldfuss.de - 10.12.1999

Zurück


Das deutsche ColdFusion-Forum cfml.de ist das Portal für Einsteiger und Experten zum Thema ColdFusion und der ColdFusion Markup Language (CFML).

© 2017 Webdesign & Hosting: CHC ONLINE Kassel | SOLVA Content-Management-System CMS
Urlaub-Angebote.de - Urlaub mit Bestpreis-Garantie buchen