AJAX ist eigentlich nichts Besonderes

Nachdem wir uns in den vergangenen Tagen auch professionell mit dem Thema AJAX befasst haben und gewissermaßen eine ganze Website mit der Logik von AJAX aufgebaut haben, fällt es leicht, auch Ihnen die Geheimnisse dieser Programmierlogik nähe zu bringen.

Dazu folgende beiden Beispiele:

Peter Fetter
Luise Zabo
Uli Katzer
Manu Rooge







Das linke Beispiel existiert seit den Anfängen von Javascript und schiebt nur die Formularinhalte von einem Feld in das andere.

Das rechte Beispiel ist neueren Datums und existiert seit dem (D)ocument(O)bject(M)odel und arbeitet mit DHTML.
Klicken Sie jetzt einmal die beiden Buttons an und beobachten Sie, was passiert. Auf der linken Seite werden nur Formularinhalte geschoben, auf der rechten Seite hingegen werden Darstellungsanweisungen mit gegeben. Wenn Sie sich die Sache nun so vorstellen, dass der obere rechte "Container" gar nicht zu sehen wäre, sondern als unsichtbares Objekt irgendwo in Ihrem Arbeitsspeicher unterwegs ist, dann können Sie sich schon die ersten Vorstellungen zum Objekttyp XMLHttpRequest machen. Allerdings wird im Unterschied zur obigen Darstellung das XMLHttpRequest Objekt flexibel gehalten und kann serverseitig mit PHP- oder ASP-Scripten bedient werden und seine Eigenschaften laufend ändern. Da aber niemand voraussehen kann, wie lange die Beantwortung der serverseitigen Anfrage dauert, wird eine "Warteschleife" aufgebaut, die Meldung erteilt, sobald die Antwort verfügbar ist und das ist natürlich mit dem obigen Beispiel nicht mehr zu vergleichen, denn oben stehen die "Antworten" bereits am Start. Wer zu diesem Zeitpunkt mehr über das XMLHttpRequest Objekt wissen möchte - hier zwei Links:

developer.apple.com (englisch)
teialehrbuch.de (deutsch)

Und nun zu unserem Beispiel - the ducks - Was sind für Routinen eingebaut?

Die erste Routine hat mit AJAX zunächst überhaupt nichts zu tun. Ich stelle sie vor, um etwas näher an das (D)ocument(O)bject(M)odell, kurz DOM heranzuführen und dieses können wir beim Einsatz von AJAX-Routinen sehr gut gebrauchen. Jedes Element in einem HTML-Dokument kann über das DOM angesprochen und dessen Eigenschaften gewissermaßen von Außen beeinflußt werden. Gängig ist die Steuerung über die Objekt-ID, welche dem Element bereits beim Aufruf in den Browser zugewiesen wird:

<Element ID="my_element">

Der Aufruf von Außen lautet dann z.B. document.all['my_element'].style.color='#7F9AAD' (Microsoft)
oder document.getElementById('my_element').style.color='#7F9AAD' (Netscape / Firefox / neuerdings auch Microsoft etc.). Was weit weniger bekannt ist: das Element weiß auch von sich selbst. Es kann immer dann direkt angesprochen werden, wenn eine Methode (ein event) dieses Elements aufgerufen wird, wie z.B. onmouseover. Genau dann kann das Element mit this. angesprochen werden und so kann mit minimalistischem Javascript der Klassenname geändert werden. Genau dieser Zusammenhang wird in der gezeigten DHTML-Routine genutzt:

<tr class='a' onmouseover=this.className='c' onmouseout=this.className='a'>

wird bereits beim Aufruf des PHP-Scripts in das XMLHttpRequest Objekt in die Eigenschaft responseText geschrieben. Was wir jetzt noch brauchen sind die drei Klassen, die wie folgt aussehen:
tr.a{background:#DDE5EC;cursor:pointer;}
tr.b{background:#FFFFFF;cursor:pointer;}
tr.c{background:#5A82A8;color:#FFFFFF;cursor:pointer;}


Damit steuern wir die Element-Eigenschaft "class=" nicht mehr von Außen sondern über den Zeiger "this." direkt aus dem Element heraus. Wichtig dabei ist der Handler className, wobei auf Groß- Kleinschreibung zu achten ist.

Tabelle 1


Und nun zu den AJAX-Routinen:

Hier wird gezeigt, wie eine Tabelle - also eine bestimmte Anzahl von Datensätzen innerhalb einer Webseite ohne neuen Seitenaufruf sortiert werden kann. Sobald auf den Tabellenkopf "Name" geklickt wird - unter der Voraussetzung, dass der richtige Radio-Button (AJAX DEMO 1) gesetzt ist, wird die Tabelle umsortiert. Die Tabellenzeile erhielt beim Aufruf der Startdatei "ajax-start.php" den onclickevent:

echo "<tr onclick=requesT_2() alt='Umsortieren' title='Umsortieren' style='font-weight:bold;cursor:pointer;'>";

Sobald Sie über den Tabellenkopf fahren, bekommen Sie einen Tip angezeigt: "Umsortieren"

alt= wurde von Microsoft jahrelang schändlich missbraucht. Eigentlich war diese Eigenschaft dazu gedacht (alt)ernative einen Schriftzug anzuzeigen, wenn das Bild nicht vom Server ausgeliefert wurde. Benutzen Sie besser title=. Das funktioniert in allen Browsern.


Die Tabelle wird nun beim Mausklick umsortiert (nur auf dem Server, wohlbemerkt) und das serverseitige Sortierergebnis wird an das XMLHttpRequest Objekt, welches in Ihrem Arbeitsspeicher bereits initiiert, ist als Eigenschaft responseText weitergeleitet. Somit können Sie über DHTML innerHTML das Ergebnis in ein bestimmtes Element in Ihrem Browser (so, wie im Beispiel oben rechts) ausgeben. Einfach oder?

Tabelle 2


Wie bereits gelesen, gibt die Datei "ajax-start.php" bei Aufruf bereits einen Eventhandler (was passiert wenn?) an den Tabellenkopf:

echo "<tr onclick=requesT_2() alt='Umsortieren' title='Umsortieren' style='font-weight:bold;cursor:pointer;'>"

Damit die Eigenschft des XMLHttpRequest Objekts überhaupt geändert werden kann, muss dieses Objekt zunächst einmal "in's Leben gerufen = initiiert" werden. Dies geschieht bereits beim Aufruf der Datei "ajax-start.php":
<script language="JavaScript">
<!--
function createReqObj(){
  brws = navigator.appName;
  if(brws == "Microsoft Internet Explorer"){
    rq = new ActiveXObject("Microsoft.XMLHTTP");
  }else{
    rq = new XMLHttpRequest(); return rq;
  }
}

rqo = createReqObj();

//-->
</script>
<noscript></noscript>
Wir können dieses Objekt rqo nun als "diplomatischen Dienst" verwenden und sagen: "sieh du mal zu, was uns der Server zu sagen hat, wenn du ihm folgende Botschaft überbringst: rqo.open('get', 'sort2.php') und melde dich danach auf Zimmer 112. In Zimmer 112 findest du ein Flipchart und darauf kannst du die Rückmeldung notieren, ohne gleich den ganzen diplomatischen Dienst zu arlamieren.

Die Funktionen requesT_2(): und receivE()

function requesT_2(){
  if(document.forms[0].elements[1].checked==false){
    alert("Bitte klicken Sie zuerst auf AJAX DEMO 1. Danke.");
    return
  }
  rqo.open('get', 'sort2.php');
  rqo.onreadystatechange = receivE;
  rqo.send(null);
}

function receivE(){
  if(rqo.readyState == 4){
    document.getElementById("liste").innerHTML = rqo.responseText;
  }
  return
}
requesT_2() prüft zunächst, ob der richtige Radio-Button eingestellt ist und wenn nicht, dann schickt sie den Anwender mit dem Auftrag zurück, zunächst einmal die richtige Einstellung vorzunehmen. ("Bitte klicken Sie zuerst auf AJAX DEMO 1. Danke."). Bei richtiger Einstellung wird mit der Methode open das Objekt rqo aufgefordert, sich auf Lesebereitschaft einzustellen, Brille aufzuziehen ("get") und sich die Datei "sort2.php" mal genau anzusehen (bzw den Inhalt dessen, was sort2.php zurückgibt). Sobald die Rückmeldung da ist, ("sort2.php") gerufen und Ausgabe gelesen: "onreadystatechange", wird die nächste Funktion receivE() aufgerufen, die gewissermaßen als Zweitkorrektor prüft, ob die Informationen vollständig sind "rqo.readyState == 4" und wenn, dann wird die Information in das Element "liste" einen <div id="liste"></div> in die aktuelle Seite übertragen.

Tabelle 3


Das gleiche Spiel funktioniert natürlich auch umgekehrt. für diesen Fall gibt die aufgerufene Datei "sort2.php" einen neuen Event-Handler aus:

echo <td onclick=requesT_1() alt='Umsortieren' title='Umsortieren'>Name  <img src='hoch.gif'/></td>

requesT_1() ruft die Datei "sort1.php", welche im Prinzip der Datei "sort2.php" gleicht und nur in der Sortierfolge abweicht:

"sort2.php" sortiert desc = aufsteigend (letzter Wert zuerst: z,y,x...)

"sort1.php" sortiert asc = absteigend (erster Wert zuerst: a,b,c...)

Und hier die zuerst gerufene Datei "sort2.php" (alle Dateien finden Sie am Ende des kleinen Tutorials):

<?php
$t_request = 'requesT_1';
$i         = 0;
$image     = 'hoch.gif';

$con = mysql_connect("host","datenbank","passwort");
if (!$con)
  {
  die('Could not connect: ' . mysql_error());
  }

mysql_select_db("db14869_198949", $con);
$result = mysql_query("SELECT id, name, strasse, ort, telefon, email FROM ducks order by name desc");

require_once("tabelle.inc");

mysql_close($con);

?>

Aber da steht ja so gut wie nichts drin in sort2.php?

Doch tut es - oben sogar rot geschrieben. Den reinen "Schreibdienst" teilen sich sort1.php und sort2.php natürlich, weil der reine "Schreibdienst" bis auf zwei Parameter ein und der selbe ist. Lediglich die auf zu rufende Methode requesT() (1 oder 2) und die Sorierung (asq oder desc) ändern sich und somit holen wir den "Schreibdienst" einfach in die jeweilige Datei mit: require_once("tabelle.inc"); hinein und müssen nur eine Datei pflegen.

Und bevor wir uns um "Oma Duck" kümmern, noch eine letzte Übung:






Und nun lernen wir eine weitere Elementeigenschaft kennen:

Eine Objekt (Element) kann sichtbar oder unsichtbar in der Seite sein, wie Sie am obigen Beispiel unschwer erkennen können. Zur Vorbereitung eines Elements (Containers, Objektes), welches später responseText darstellen soll, braucht man das Element ja nicht gleich zu zeigen. So ist das im Beispiel der Familie Duck. Der unsichtbare Container liegt exakt unter der Tabelle mit den Dateninhalten plaziert. Die Eigenschaft sichtbar oder unsichtbar ist die visibillity:

  • visibility = 'visible' = wird angezeigt
  • visibility = 'hidden' = wird versteckt


  • Da wir im obigen Beispiel das Element mit seiner "id=oma" ansprechen, lautet der Javascript-Code ganz einfach:
    
    <script language="JavaScript">
    <!--
    function oma() {
      if(document.forms[0].elements[4].value=='Zeige die Oma') {
        document.forms[0].elements[4].value='Verstecke die Oma';
        document.getElementById('oma').style.visibility='visible';
      } else {
        document.forms[0].elements[4].value='Zeige die Oma';
        document.getElementById('oma').style.visibility='hidden';
      }
    return
    }
    //-->
    </script>
    <noscript></noscript>
    
    


    Tabelle 4


    Und was hat das mit unserem AJAX-Beispiel zu tun?

    Nun, wir können den den Server anrufen und nach bestimmten Inhalten abfragen Beschreibung (legend) und Bild (image). Wir warten, bis der Server die Inhalte an unseren responseText des XMLHttpRequest Objektes rqo ausgeliefert hat, zeigen dann den (vorher) unsichtbaren
    <DIV id="my_div"> an und füllen ihn mit den Inhalten aus responseText.

    Eigentlich ist eine Tabelle auch ein Element. Nur nicht für Microsoft. Wenn Sie versuchen einen Text über "innerHTML" in eine Tabelle im MS-Internetexplorer zu schreiben, wird dies jämmerlich misslingen. Darum immer schön mit "<DIV>" arbeiten.

    Und nun zum Rest:



    Ein Klick auf einen bestimmten Datensatz der Tabelle bewirkt, wenn AJAX DEMO 2 eingestellt wurde, folgendes:

    <tr onClick=requesT_3(this.id)></tr>

    und requesT_3() hat den Inhalt:
    
    function requesT_3(wert){
      if(document.forms[0].elements[2].checked==false){
        alert("Bitte klicken Sie zuerst auf AJAX DEMO 2. Danke.");
        return
      }
      rqo.open('get', 'sort3.php?id='+wert);
      rqo.onreadystatechange = receivE_2;
      rqo.send(null);
    }
    function receivE_2(){
      if(rqo.readyState == 4){
        document.getElementById("my_div").style.visibility = "visible";
        document.getElementById("my_div").innerHTML = rqo.responseText;
      }
      return
    }
    
    
  • Prüfen, ob der Radio-Button "AJAX DEMO 2" eingestellt ist, wenn nicht zurückschicken
  • sort3.php zur Ausgabe von Beschreibung und Bild rufen
  • Warten, bis die Antwort kommt
  • <div id="my_div"> anzeigen
  • Erhaltene Antwort in <div id="my_div"> schreiben - that's it


  • So, und zum Abschluss, wie immer noch die verwendeten Dateien:

    Zunächst die Tabelle:

    Bilder und vollständige Textinhalte können Sie vom Beispiel kopieren

    Daten


    Zugehörige Dateien (immer den entsprechende Abschnitt kopieren und unter dem angegebenen Dateinamen speichern):

    ajax-start.php     sort1.php     sort2.php     sort3.php     tabelle.inc     style.css