Ajax-Anwendung mit Javascript und PHP
Daten ohne Refresh nachladen

DeveloperIT-ProjekteSoftware

So genannte Ajax-Web-Applikationen laden mit Hilfe eines Javascript-Objekts dynamisch Daten vom Webserver und stellen sie im Browser dar. Der Workshop gibt eine Einführung in diese neue Technik der Webseitenprogrammierung.

Der neue Hype

Ajax-Anwendung mit Javascript und PHP

Es gibt heutzutage nicht mehr viele neue Trends und Hypes im Internet. Wer als Web-Entwickler die letzten Monate nicht komplett offline verbracht hat, wird aber bestimmt schon über den Begriff Ajax-Web-Anwendungen gestolpert sein. Ajax steht wahlweise für Advanced Javascripting and XML oder Asynchronous Javascripting and XML und propagiert eine völlig neue Art der Webseitenprogrammierung. Interessanterweise kommen dabei nur Techniken zum Einsatz, die bereits einige Jahre auf dem Buckel haben, namentlich Javascript, XML sowie das XMLHttpRequest-Object. Mit Hilfe dieses Objekts lassen sich unter Javascript dynamisch Web-Anfragen an einen Webserver senden, der die Resultate als XML zurückliefert. Diesen XML-Code wertet man dann wieder mit Javascript aus und stellt die Ergebnisse im Browser dar.

Das klingt zugegebenermaßen auf den ersten Blick wenig spektakulär, ermöglicht aber eine vollkommen neue Art der Programmierung von Web-Anwendungen. Bisher war man als Entwickler beim Nachladen von neuen Daten immer auf einen neuen Seitenaufbau angewiesen. Das hat gleich mehrere Nachteile: Die Bedienoberfläche des Users verschwindet und wird neu aufgebaut, der gesamte Quelltext des Dokuments muss neu übertragen werden, und serverseitig ist eine komplexe Programmierung notwendig, um Design, User-Events und Datenanfragen sauber voneinander zu trennen.


Ohne Refresh: Ajax

Ajax-Anwendung mit Javascript und PHP

Mit Hilfe der Ajax-Technik verschwindet diese Einschränkung: Es ist sogar möglich neue Daten vom Server zu laden, während der Benutzer gerade Eingaben vornimmt. Ein eindrucksvolles Beispiel dazu liefert Google Suggest (www.google.com/webhp?complete=1&hl=en): Während der Eingabe des Suchbegriffs erscheinen bereits automatisch vervollständigt die häufigsten Suchanfragen dazu. Ajax bietet noch weitere Vorteile: Da die Darstellung und Aktualisierung der Daten komplett im Browser stattfindet, wird zum einen der Webserver entlastet, zum anderen ist eine klare Trennung zwischen Darstellungs- und Datenschicht definiert. Der Webserver kümmert sich dabei hauptsächlich um die Datenbankanfragen und liefert diese als XML zurück. Als serverseitige Skriptsprache lässt sich jede Technik einsetzen, mit der man XML-Daten zurückliefern kann (ASP, PHP, JSP, Python et cetera).

Auf der Negativseite von Ajax steht eine relativ komplexe und komplizierte Programmierung in Javascript, wobei sehr gute Kenntnisse des Document Object Model (DOM) erforderlich sind. Dieser Workshop geht deshalb behutsam Schritt für Schritt vor und startet mit sehr einfachen, kleinen Beispielen.


XMLHttpRequest im Browser

Ajax-Anwendung mit Javascript und PHP

Dreh- und Angelpunkt von Ajax ist das Objekt XMLHttpRequest. Mit diesem Objekt öffnen Sie eine HTTP-Verbindung zur einem URL und lesen die zurückgelieferten Daten aus. Leider ist das Objekt kein Teil eines W3C-Standards, so dass die Browser-Implementierungen für Internet Explorer und die anderen Browser sich unterscheiden. Glücklicherweise sind aber die Methoden und Eigenschaften in allen Browsern so gut wie identisch.

Im Internet Explorer instanziieren Sie das Objekt mit Hilfe eines ActiveX-Objekts:

xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

In allen anderen Browsern erfolgt der Aufruf mit:

xmlhttp = new XMLHttpRequest();

Damit die Implementierung Browser-unabhängig bleibt, verwenden Sie am besten eine try-Abfrage beim Anlegen des Objekts, fangen den Fehler ab und implementieren im catch-Block die andere Variante:


try
{ xmlhttp = new XMLHttpRequest(); }
catch (error)
{ try
{ xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
}


Argumente übergeben

Ajax-Anwendung mit Javascript und PHP

Nachdem das Objekt angelegt ist, können Sie mit der Methode open() eine HTTP-Anfrage losschicken. Das erste Argument beschreibt dabei die verwendete Methode der Datenübertragung (GET oder POST ähnlich wie bei Formularen). Bei GET senden Sie die Daten über den URL, weshalb die Daten 512 Byte Größe nicht überschreiten sollten. Das zweite Argument gibt der URL an. Ein Beispiel:

xmlhttp.open("GET", "userdata.xml");

Zusätzliche Variablen übergeben Sie dabei wie bei normalen Webseiten im URL, also zum Beispiel:

xmlhttp.open("GET", "get_userdata.php?id=441&category=2");

Natürlich können Sie den URL auch dynamisch mit Javascript zusammenbauen. Ein einfaches Beispiel nimmt
die Eingabe aus einem Formularfeld mit dem Namen
username und übergibt sie an den URL als Variable name. Achten Sie darauf, Inhalte, die über den URL gesendet werden, mit der Methode escape() zu kodieren:

xmlhttp.open("GET", "get_userdata.php?name=" + escape
(document.forms[0].username.value));

Nachdem die Verbindung mit open() geöffnet wurde, sorgt die Methode send() für das Absenden der Daten. Als Argument sollten Sie null an Stelle der leeren Klammer verwenden, da es sonst zu einem Fehler in Mozilla kommen kann: _xmlhhtp.send(null).

Wenn Sie open() mit der Methode POST aufgerufen haben, werden die Daten als Argument der send-Methode angegeben. Also zum Beispiel:


xmlhhtp.open("POST", "/get_userdata.php");
xmlhhtp.send("id=44&category=2");


Daten empfangen

Ajax-Anwendung mit Javascript und PHP

Ein xmlhttp-Request läuft asynchron ab, das heißt er wird im Hintergrund bearbeitet, während der Browser weiter auf Benutzereingaben reagiert und Javascript-Code ausführt. Das ist auch gut so, denn sonst wäre die gesamte Bedienoberfläche blockiert (die open-Methode lässt aber auch synchrone Aufrufe zu, mehr dazu in der API-Definition des Objekts). Um festzustellen, wann die Anfrage beendet wurde und die Daten angekommen sind, ist es notwendig, einen Event-Listener zu verwenden. Der aktuelle Status des xmlhttp-Objekts wird über die Variable readyState abgefragt. Hier werden Werte von 0 bis 4 zurückgegeben. Interessant ist nur der Wert 4, der anzeigt, dass alle Daten empfangen wurden.

Sobald sich der Wert in readyState ändert, wird der Event-Handler onreadystatechanged aufgerufen. Diesem muss man vorher eine eigene Javascript-Routine zuweisen, zum Beispiel:

xmlhttp.onreadystatechange = handleHttpState;

In der Funktion handleHttpState prüfen Sie den Wert von readyState und fahren nur dann fort, wenn dieser gleich 4 ist.

Als zweite Abfrage sollten Sie die Variable status überprüfen: Hier wird der HTTP-Statuscode zurückgegeben. Wenn dort ein anderer Wert als 200 (für OK) vorliegt, ist ein Fehler bei der Anfrage aufgetreten, beispielweise der bekannte Code 404 für Not Found. Die Variable statusText enthält im Übrigen den Fehlertext.

In der Funktionsdefinition rufen Sie die Funktion parseData() auf, sobald die Daten vollständig erfolgreich geladen wurden:


function handleHttpState()
{
if (xmlhttp.readyState == 4)
{
if (xmlhttp.status == 200) {
parseData();
} else {
alert("Fehler beim Abrufen der XML Daten");
}
}
}


Daten auswerten

Ajax-Anwendung mit Javascript und PHP

Sobald die Daten erfolgreich vom Server empfangen wurden, folgt mit der Auswertung der Daten der interessantere Teil der Programmierung. Alle bisher vorgestellten Funktionen können Sie in beinahe jeder Ajax-Anwendung verwenden. Die Auswertung der Daten und die Anzeige im Browser wird aber in jeder Anwendung unterschiedlich sein.

Im ersten, sehr einfachen Beispiel wird lediglich überprüft, ob ein Benutzername bereits im System vergeben ist. Der Server liefert daher nur die Werte vergeben oder frei zurück, der Einfachheit halber ohne XML-Struktur.

Die gelieferten Daten stehen nach dem erfolgreichen Request als Text in der Variable responseText zur Verfügung ? oder als XML-Objekt in der Variable responseXML. In parseData() verwenden Sie responseText zur Überprüfung des Rückgabewerts und geben eine Javascript-Meldung aus, falls der Name schon vergeben ist:


function parseData()
{
var response = xmlhttp.responseText;
if(response != "frei") {
alert("Der Benutzername ist bereits vergeben");
document.forms[0].username.value="";
}
}

Im Formular rufen Sie die Javascript-Methode zur Überprüfung des Benutzernamens im Event Handler onchange() des Input-Tags auf. Dadurch wird der eingegebene Name sofort überprüft, wenn der Benutzer in das Feld zur Passworteingabe wechselt. Die zugehörige Funktion check_username() liest den eingegebenen Namen aus dem Formular aus und sendet ihn an das PHP-Skript check_username.php:


var check_name = document.forms[0].username.value;
if( check_name != "") {
getXMLData("check_username.php?username=" + escape(check_name));
}

Dort findet die Überprüfung des Namens statt. Im vorliegenden Beispiel stehen die bereits belegten Benutzernamen mzierl, admin und guest im Klartext im PHP-Code. Hier sollte natürlich sinnvollerweise eine Datenbankabfrage auf die Benutzertabelle erfolgen.


XML-Dokumente parsen

Ajax-Anwendung mit Javascript und PHP

Interessanter wird es, wenn man größere Datenmengen als XML-Struktur vom Server erhält und diese im Browser anzeigt. Im nächsten Beispiel liefert der Server per PHP die folgende XML-Struktur mit Urlaubsorten und zugehörigen Datenbank-IDs zurück:




32
Barcelona


7
Borkum

...

In der Methode parseData() werden diese Daten ausgelesen und einem SELECT-Element hinzugefügt. Über xmlhttp.responseXML erhalten Sie ein XML-Objekt, das Sie in der Variable xmlDocument speichern. Mit den Standard-Methoden des Document Object Model lassen sich anschließend die Elemente des XML-Baums durchlaufen und die Inhalte extrahieren. Dazu verwendet man am besten die Methode getElementsByTagName(?xml_tag?), um ein Array aller Elemente mit einem bestimmten Tag-Namen zu erhalten. Im Beispiel durchlaufen Sie mit einer for-Schleife alle data-Elemente und extrahieren dann die darin enthaltenen Werte der Tags id und name. Alle Elemente der XML-Struktur sind intern als Knoten (nodes) mit darin enthaltenen Unterknoten (children) dargestellt. Da der Text eines XML-Elements wiederum in einem Text-Knoten (text_NODE) enthalten ist, erhalten Sie den Inhalt, ausgehend vom Element, mit firstChild.nodeValue. Die komplette Schleife sieht dann folgendermaßen aus:


for(var i=0; i< xmlDocument.getElementsByTagName("data").length; i++)
{
var base = xmlDocument.getElementsByTagName("data")[i];
var id = base.getElementsByTagName("id")[0].firstChild.nodeValue;
var name = base.getElementsByTagName("name")[0].firstChild.nodeValue;
add_element(select_obj, id, name);
}

Die Funktion add_element() fügt die gelesenen Name/ID-Kombinationen einem HTML-SELECT-Element hinzu. Dazu erzeugt man mit document.createElement(?option?) ein neues option-Objekt, setzt die Attribute für value und text und ruft dann die add-Methode des Select-Objekts auf:


function add_element(obj, id, name)
{
var new_opt = document.createElement("option");
new_opt.value = id;
new_opt.text = name;
obj.add(new_opt);
}


XML dynamisch erzeugen

Ajax-Anwendung mit Javascript und PHP

Das abschließende Beispiel ist etwas praxisbezogener und generiert die Inhalte dynamisch aus einer Datenbankabfrage. In einem Reisebuchungsformular wählt der Benutzer dazu nacheinander Reiseland, Region und Reiseort aus. Nach jeder einzelnen Auswahl werden dynamisch die jeweiligen Unterkategorien vom Server geladen und angezeigt. Nach Auswahl des Landes sehen Sie also beispielsweise die Regionen des Landes, und nach Auswahl der Region die jeweiligen Städte beziehungsweise Reiseziele.

Die Daten liegen dabei in einer Access-Datenbank, die sich zusammen mit den Listings ebenfalls auf der Heft-CD befindet. Da die PHP-Skripts zur Erzeugung des XML-Codes sehr einfach gehalten sind und im Internet Tools zur Konvertierung von Access nach MySQL erhältlich sind, sollte der Wechsel auf eine andere Datenbank keine Probleme bereiten. Jede andere Skriptsprache, die in der Lage ist, XML-Daten zurückzuliefern, lässt sich natürlich ebenfalls einsetzen. Die Daten befinden sich in den Datenbank-Tabellen countries, regions und destinations. Wie im zweiten Beispiel stehen die Informationen in den Feldern id und name bereit. Zusätzlich besitzen die Tabellen regions und destinations je ein zusätzliches Feld country_id beziehungsweise region_id, welches das Land der Region respektive die Region, in der sich das Reiseziel befindet, bestimmt.

Bei der Ausgabe von XML-Daten mit PHP ist es vor allem wichtig, dass der Mime-Typ im Header mit

header('Content-Type: text/xml');

richtig gesetzt wird. Die erste Zeile der XML-Daten sollte

lauten, danach erzeugen Sie die XML-Tags einfach mit den Befehlen print oder echo. Auf die genauen Datenbankabfragen und das Auslesen der URL-Variablen mit PHP soll hier nicht weiter eingegangen werden ? dazu gibt es genügend andere Artikel. Gehen Sie im folgenden Beispiel einfach davon aus, dass die verwendete Datenbank-Tabelle über die URL-Variable type und die jeweils zugehörige ID des Landes oder der Region mit der URL-Variable id an das PHP-Skript übergeben wird. Die XML-Ausgabe ist strukturell identisch zum Beispiel 2, das heißt die Inhalte werden in den Tags id und name zurückgeliefert.


Auswahl aktualisieren

Ajax-Anwendung mit Javascript und PHP

Nach dem Laden der Seite lädt ein Skript zuerst über das onload-Event des Body-Tags alle Reiseländer und zeigt sie in der ersten Select-Box an. Sobald der Benutzer auf einen Ländernamen klickt, sollen dynamisch die jeweiligen Regionen des Landes nachgeladen und in der zweiten Auswahlbox angezeigt werden. Dazu setzt man den onchange-Event des Select-Objekts auf die zugehörige Javascript-Funktion. In diesem Beispiel sieht das folgendermaßen aus:



Die Funktion get_select_data() baut dann zuerst aus dem als zweites Argument übergebenen URL und dem als dritten Argument übergebenen Namen des ausgewählten Feldes den URL für die Datenbankanfrage zusammen. Die jeweils ausgewählte ID des Landes erhalten Sie, indem Sie den aktuellen Wert der Reiseland-Auswahlliste auslesen und als id an den PHP-URL übergeben:

url += "&id=" + eval("document.forms[0]." + selected_id + ".value");

Das Auslesen und Hinzufügen der XML-Daten erfolgt dann genauso wie im Beispiel 2. Einziger Unterschied: Die Variable active_select_obj enthält jeweils eine Referenz auf die jeweils neu aufzufüllende Auswahlliste. Der Name dieser Auswahlliste wird als erstes Argument von get_select_data() übergeben.

Um das Objekt der Variable zuzuweisen, bedienen Sie sich dann wieder der eval-Funktion von Javascript. Das geht folgendermaßen:

active_select_obj = eval("document.forms[0]." + select_name);

Nach einem Klick auf den Reiseort erscheint eine Liste der verfügbaren Hotels, die in diesem Beispiel aus Platzgründen wieder als statische XML-Datei definiert ist, so dass bei jeder Auswahl die gleichen Hotels erscheinen. Sinnvollerweise sollte hier auch wieder eine Datenbankabfrage stehen.

Die Hotelliste wird als HTML-String angelegt und über das innerHTML-Attribut eines div-Containers angezeigt.


Fazit

Ajax-Anwendung mit Javascript und PHP

Mit Ajax lassen sich Web-Anwendungen entwickeln, die schneller und direkter auf Benutzereingaben reagieren als die bisherigen, auf das Neuladen der Seite angewiesenen Applikationen. Der Nachteil ist allerdings die recht komplexe Javascript-Programmierung und das damit verbundene unkomfortable Debugging. Abhilfe schaffen hier eventuell die zahlreichen in Entwicklung befindlichen Ajax-Librarys, die allerdings oft auf serverbasierten Techniken wie JSP oder ASP.NET aufsetzen.