Posts mit dem Label Ajax werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Ajax werden angezeigt. Alle Posts anzeigen

Montag, 27. August 2007

Tutorial: Ajax (9)

siehe auch:
(1): Was ist Ajax?
(2): Warum heißt Ajax so? Wo kann ich Ajax in Aktion sehen?
(3): Worin besteht die Ajax-Schnittstelle? Wie wird Ajax standardisiert?
(4): Welche Nachteile hat Ajax? Wie sicher ist Ajax?
(5): Ein einfacher Ajax-Kernel
(6): Eigenschaften und Methoden des XMLHTTPRequest-Objekts
(7): Ajax-Beispiel: Formularüberprüfung
(8): Ajax-Beispiel: Tabellensortierung


Dies ist der letzte Teil des Ajax-Tutorials!

Das Ajax-Tutorial downloaden:
http://groups.google.com/group/webkompetenz/web/Ajax.pdf (ca. 388 KByte)

PDF-Reader erforderlich!

Ajax-Bibliotheken und Frameworks

Tausendfach bewährter Code ist immer sicherer als neu erstellter. Deshalb gehört es in der Programmierung zum guten Ton, im Zweifelsfall auf vorhandenen Code zurückzugreifen. Zu diesem Zweck gibt es Code-Bibliotheken. Je mehr Fälle solche Code-Bibliotheken abdecken, desto bestimmender werden sie für die Anwendungsprogrammierung. Bei umfassenden Code-Bibliotheken spricht man deshalb auch von Frameworks.

Wenn Sie Ajax nur an einer oder wenigen Stellen benötigen, sind eigene Scripts meist performanter und übersichtlicher. Wenn Sie jedoch planen, eine Ajax-intensive Webanwendung zu entwickeln, lohnt sich der Aufwand, sich in das „Bedienen“ eines Frameworks einzuarbeiten.

Nachfolgend ausgewählte Produkte laufen unter OpenSource-Lizenzen (Details sind den jeweiligen Websites zu entnehmen). Es handelt sich nicht nur um reine Ajax-Bibliotheken, sondern um Bibliotheken, die in der Regel auch andere client-seitige Scriptaufgaben mit übernehmen, wie Event-Handling, DOM-Zugriffe oder Dialogelemente wie Menüs, Listen usw. Die Frameworks sind in aller Regel gut dokumentiert, da der Erfolg eines Frameworks letztlich daran hängt, wie leicht der Zugang dazu fällt.

  • Dojo:
    http://www.dojotoolkit.org/
    Sehr umfangreiches Framework zur Erstellung anspruchsvoller Webanwendungen, aber auch für speziellere Aufgaben wie XML-Parser, SVG-Grafik-Umsetzung, Validierung von Internetadressen, Widget-Builder und vieles mehr. Eine spezielle Ajax- Edition von Dojo wird angeboten.
  • jQuery:
    http://jquery.com/
    Framework, das konsequent die JavaScript-Objektstruktur erweitert und besonders den gesamten DOM-Bereich für Programmierer vereinfachen will. Enthält auch ein leistungsfähiges Ajax-Modul für alle HTTP-Methoden.
  • Prototype:
    http://prototype.conio.net/
    Objektorientierte Bibliothek für Bereiche wie DOM-Zugriffe, Event-Handling, Formularkontrolle und eben auch Ajax. Bei Ajax werden alle HTTP-Methoden für Requests unterstützt. Auch für dynamische periodische Aufrufe, wie im Zusammenhang mit dem web-basierten Chat von Fritz Weisshart beschrieben, werden unterstützt.
  • Qooxdoo:
    http://qooxdoo.org/
    Auf die Entwicklung von web-basierten, Ajax-unterstützten Anwendungen spezialisierte JavaScript-Bibliothek.

Abschließend noch einige ausgewählte Webadressen, die sich mit Ajax näher befassen.

Offizielle Quellen

  • W3-Konsortium: Spezifikation des XML-HTTP-Request-Objekts
    http://www.w3.org/TR/XMLHttpRequest/
    Maßgeblich dafür, wie das für Ajax verantwortliche XML-HTTP-Objekt in Browsern implementiert sein sollte.

Deutschsprachige Quellen

Internationale Quellen


Dienstag, 17. Juli 2007

Tutorial: Ajax (8)

siehe auch:
(1): Was ist Ajax?
(2): Warum heißt Ajax so? Wo kann ich Ajax in Aktion sehen?
(3): Worin besteht die Ajax-Schnittstelle? Wie wird Ajax standardisiert?
(4): Welche Nachteile hat Ajax? Wie sicher ist Ajax?
(5): Ein einfacher Ajax-Kernel
(6): Eigenschaften und Methoden des XMLHTTPRequest-Objekts
(7): Ajax-Beispiel: Formularüberprüfung


Ajax-Beispiel: Tabellensortierung

Das Sortieren von Tabellen ist zwar mit etwas Aufwand auch direkt in JavaScript möglich. Doch dabei lauern zahlreiche Tücken, beispielsweise, wenn zu sortierende Einträge zusätzlich in Links verpackt werden sollen. Wenn die Daten der Tabelle aus einer Datenbank kommen, bietet sich Ajax als Alternative an. Wie so etwas aussehen kann, beschreiben wir im nachfolgenden Beispiel.

Tabellarische Daten aus einer Datenbank

Für unser Beispiel greifen wir auf die MySQL-Datenbank mit dem Namen cms aus dem ersten Beispiel zurück. Wir nehmen eine Tabelle namens users an, in der zugangsberechtigte Benutzer gespeichert sind. Aktuell seien dort unter anderem folgende Daten gespeichert:

+----+-----------------------+-----------------+---------------------+
| id | index_name            | group_name      | last_login          |
+----+-----------------------+-----------------+---------------------+ 
|  1 | Lyse, Anna            | developers      | 2007-07-12 09:27:23 |
|  2 | Wahnsinn, Reiner      | editors         | 2007-06-28 13:02:01 |
|  3 | Dolegstdinieder GmbH  | service-editors | 2007-06-28 13:56:39 |
|  4 | Error, Erika          | editors         | 2007-07-08 10:03:56 |
|  4 | Krieg, Frieda         | admins          | 2007-07-12 21:11:21 |
+----+-----------------------+-----------------+---------------------+

Die id-Spalte speichert Autoincrement-Werte. Die Spalte index_name enthält die Namen der Benutzer in einer Darstellungsform, die für eine sinnvolle alphabetische Sortierung optimal ist. In group_name werden Benutzergruppen gespeichert, denen die Benutzer zugeordnet sind. In der Spalte last_login wird der Zeitpunkt des letzten Logins eines Benutzers in einer für die Sortierung brauchbaren Form gespeichert.

Serverseitig setzen wir wieder ein PHP-Script ein, das die Datenbankabfrage besorgt. Außerdem bereitet das Script die HTML-Tabelle auf. Im HTML-Dokument wird wieder unser Ajax-Kernel eingebunden. In der ajax.js notieren wir der Einfachheit halber auch die Funktion zum Steuern der Tabellensortierung.

Basis-Dokument (PHP)

Vom Server lassen wir zunächst eine PHP-Datei (nennen wir sie z.B. index.php) ausliefern:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="de">
<head>
<title>Test</title>
<script type="text/javascript" src="ajax.js"></script>
</head>
<body>
<h1>Benutzer</h1>
<div id="user_list">
<?php
include("./userSort.php");
?>
</div>
</body>
</html>

Das „Script“ besteht vorwiegend aus gewöhnlichem, statischem HTML-Code. Lediglich an einer Stelle im Code ist ein PHP-Bereich notiert. Dort wird das Script userSort.php eingebunden. Im HTML-Kopfbereich wird das externe JavaScript ajax.js eingebunden.

Das HTML-Dokument besteht im sichtbaren Bereich nur aus einer Überschrift und einem div-Bereich mit dem id-Namen user_list. Diesen id-Namen werden wir verwenden, um in den entsprechenden div-Bereich die sortierte Tabelle zu platzieren.

Bevor das HTML-Dokument an den aufrufenden Browser gesendet wird, wird auf dem Server der Inhalt des PHP-Bereichs () durch den HTML-Code ersetzt, den das mit include eingebundene PHP-Script userSort.php erzeugt. Sehen wir uns dieses Script deshalb als nächstes an.

Serverseitiges Sortier-Script (PHP)

Der Code des Scripts userSort.php lautet wie folgt:

<?php

$dbh = mysql_connect("localhost", "dbuser", "dbpassword");
if(!$dbh) {
   echo "<div>Keine Verbindung zum Datenbank-Management-System"; 
   exit();
}
$sql = "USE cms";
$sqlResult = @mysql_query($sql, $dbh);
if(!$sqlResult) {
   echo "<div>Keine Verbindung zur Datenbank</div>"; 
   exit();
}
if(! isset($_GET['field']) or 
  ($_GET['field'] != "index_name" and $_GET['field'] != "group_name" 
   and $_GET['field'] != "last_login"))
   $sortField = "index_name";
else 
   $sortField = $_GET['field'];
if(! isset($_GET['order']) or ($_GET['order'] != "asc" and $_GET['order'] != "desc"))
   $sortOrder = "asc";
else 
   $sortOrder = $_GET['order'];

$data = array();
$sql = "SELECT * FROM users ORDER BY " . $sortField . " " . $sortOrder;
$sqlResult = @mysql_query($sql, $dbh);
if(!$sqlResult) {
   echo "<div>Kein Datenbankergebnis</div>";
   exit();
}
else 
   while($record = mysql_fetch_array($sqlResult, MYSQL_ASSOC))
      $data[] = $record;
if(empty($data)) {
   echo "<div>Die Tabelle enthält keine Daten</div>";
   exit();
}

$tableHTML = "<table border=\"1\">\n";
$tableHTML .= "<tr>\n";
$tableHTML .= "<th class=\"tlist\">Name ";
$tableHTML .= "<a href=\"javascript:ajaxUserSort('index_name', 
                                         'asc', 'user_list')\">&#x25B2;</a> ";
$tableHTML .= "<a href=\"javascript:ajaxUserSort('index_name', 
                                         'desc', 'user_list')\">&#x25BC;</a>";
$tableHTML .= "</th>\n";
$tableHTML .= "<th class=\"tlist\">Benutzergruppe ";
$tableHTML .= "<a href=\"javascript:ajaxUserSort('group_name', 
                                         'asc', 'user_list')\">&#x25B2;</a> ";
$tableHTML .= "<a href=\"javascript:ajaxUserSort('group_name', 
                                         'desc', 'user_list')\">&#x25BC;</a>";
$tableHTML .= "</th>\n";
$tableHTML .= "<th class=\"tlist\">Letztes Login ";
$tableHTML .= "<a href=\"javascript:ajaxUserSort('last_login', 
                                         'asc', 'user_list')\">&#x25B2;</a> ";
$tableHTML .= "<a href=\"javascript:ajaxUserSort('last_login', 
                                         'desc', 'user_list')\">&#x25BC;</a>";
$tableHTML .= "</th>\n";
$tableHTML .= "</tr>\n";
$tableHTML .= "[%tableAllRows%]\n";
$tableHTML .= "</table>\n";

$tableRowHTML  = "<tr>\n";
$tableRowHTML .= "<td><a href=\"?showUser.php?id=[%id%]\">[%index_name%]</a></td>\n";
$tableRowHTML .= "<td><a href=\"?showGroup.php?name=[%group_name%]\">[%group_name%]</a></td>\n";
$tableRowHTML .= "<td>[%last_login%]</td>\n";
$tableRowHTML .= "</tr>\n";

$tableAllRowsHTML = "";
foreach($data as $record) {
   $recordHTML = $tableRowHTML;
   $recordHTML = str_replace("[%index_name%]", $record['index_name'], $recordHTML);
   $recordHTML = str_replace("[%group_name%]", $record['group_name'], $recordHTML);
   $recordHTML = str_replace("[%last_login%]", $record['last_login'], $recordHTML);
   $recordHTML = str_replace("[%id%]", $record['id'], $recordHTML);
   $tableAllRowsHTML .= $recordHTML;
}
$tableHTML = str_replace("[%tableAllRows%]", $tableAllRowsHTML, $tableHTML);

echo $tableHTML;

?>

Das Script versucht zunächst eine Verbindung zu MySQL herzustellen. Im Fehlerfall gibt es eine entsprechende Meldung aus und wird beendet. Anschließend setzt es das SQL-Statement USE cms ab, um die CMS-Datenbank unseres Beispiels auszuwählen. Auch hier wird im Fehlerfall eine Meldung ausgegeben und das Script beendet.

Als nächstes wird geprüft, ob das Script mit GET-Parametern aufgerufen wurde. Denn über die GET-Parameter field und order erfährt das Script, nach welcher Tabellenspalte ($_GET['field']) und in welcher Sortierrichtung ($_GET['order']: aufsteigend = asc oder absteigend = desc) sortiert werden soll. Fehlen die GET-Parameter, werden Defaultwerte (Feld index_name und Sortierrichtung asc) festgesetzt. Genau das, also der Aufruf ohne GET-Parameter, geschieht beim ersten Aufruf des Scripts mit der include-Anweisung im Basis-Dokument, die wir weiter oben bereits beschrieben haben.

Nachdem die Parameterfrage geklärt ist, wird ein Array namens $data initialisiert. In diesem Array werden die Daten gespeichert, die MySQL liefern soll. Der Grund, weshalb wir für dieses Beispiel Ajax einsetzen, ist ja, dass wir MySQL die Sortierung der Daten überlassen. Deshalb bauen wir das SQL-Statement zur Abfrage der Tabelle users so zusammen, dass sich die gewünschte Sortierung ergibt:

$sql = "SELECT * FROM users ORDER BY " . $sortField . " " . $sortOrder;

Die Variablen $sortField und $sortOrder wurden ja zuvor mit den Werten der GET-Parameter field und order oder mit Default-Werten versorgt. Je nach übergebenen GET-Parametern können also SQL-Statements entstehen wie beispielsweise:

$sql = "SELECT * FROM users ORDER BY last_login desc";

MySQL liefert die Daten in der gewünschten Sortierreihenfolge aus. Falls ein Fehler auftritt, wird wieder eine Meldung ausgegeben, und das Script wird beendet. In einer while-Schleife werden die von MySQL gelieferten Datensätze in den Array $data eingelesen.

In der zweiten Hälfte des Scripts userSort.php wird der HTML-Code der auszugebenden Tabelle zusammengesetzt. In der Variablen $tableHTML wird zunächst das Grundgerüst der Ausgabetabelle gespeichert. An der Stelle, wo die Zeilen der Tabelle mit den auszugebenden Datensätzen stehen sollen, haben wir einen Platzhalter namens [%tableAllRows%] notiert, der später ersetzt wird. In der Variablen $tableRowHTML wird der HTML-Code einer einzelnen Tabellenzeile gespeichert. Auch dort arbeiten wir mit Platzhaltern der Marke Eigenbau, nämlich [%id%], [%index_name%], [%group_name%] und [%last_login%]. Dann wird die Variable $tableAllRowsHTML initialisiert. In einer foreach-Schleife wird nun der Array $data abgearbeitet. Bei jedem Schleifendurchlauf wächst der Inhalt der Variablen $tableAllRowsHTML um den Wert von $recordHTML. In $recordHTML wird jeweils eine frische Version von $tableRowHTML gespeichert. Dann werden die darin enthaltenen Platzhalter durch die tatsächlichen Daten des jeweils abgearbeiteten Datensatzes ersetzt. Am Ende muss dann nur noch in $tableHTML der Platzhalter [%tableAllRows%] durch $tableAllRowsHTML ersetzt werden. Die fertige HTML-Tabelle mit den sortierten Daten wird in einem Stück mit echo $tableHTML ausgegeben.

JavaScript zur Steuerung der Sortierung

Doch wie kommt nun die für den Anwender so komfortable Möglichkeit zustande, die Tabelle während der Anzeige im Browser zu sortieren? Dazu werfen wir einen Blick auf die Tabelle, die das Sortierscript ausgibt:

sortierte Tabelle

Im HTML-Code der ausgegebenen Tabelle sind neben den Spaltenüberschriften jeweils zwei Links notiert, die durch die Symbole ▲ und ▼ aus dem erweiterten Unicode-Bereich das Sortieren der Tabelle nach der jeweilgen Spalte in der jeweiligen Sortierrichtung ermöglichen. Jeder dieser Links definiert einen JavaScript-Aufruf, zum Beispiel:

<a href="javascript:ajaxUserSort('index_name', 'asc', 'user_list')\">&#x25B2;</a>

Es wird eine JavaScript-Funktion namens ajaxUserSort() aufgerufen. Dieser Funktion werden drei Parameter übergeben. Der erste Parameter ist der Datenbankname der Tabellenspalte, nach der sortiert werden soll. Der zweite Parameter bestimmt die Sortierrichtung, und der dritte Parameter gibt den id-Namen des HTML-Elements an, als dessen Inhalt die fertig erzeugte Tabelle eingefügt werden soll. Im obigen Beispielaufruf soll also nach der Tabellenspalte index_name (= „Name“) aufsteigend (asc) sortiert werden. Das Ergebnis soll als Inhalt des Elements mit dem id-Namen user_list ausgegeben werden.

Die Funktion ajaxUserSort notieren wir der Einfachheit halber wieder in ajax.js, wo auch der Code des Ajax-Kernels notiert ist. Der Code dieser Funktion lautet:

function ajaxUserSort(sortField, sortOrder, outputId) {
   if(!document.getElementById)
      return;
   if(sortOrder != "asc" && sortOrder != "desc") {
      document.getElementById(output_id).innerHTML = 
           "<span class=\"errortext\">Ungültige Angabe zur Sortier-Richtung!</span>";
      return;
   }
   scriptUrl = "http://localhost/ajax-test/userSort.php";
   paramStr = "?field=" + sortField + "&order=" + sortOrder;
   doHttpRequest(scriptUrl + paramStr, outputId);
}

Die Funktion prüft zunächst, ob die DOM-Methode getElementById verfügbar ist. Falls nicht, kann das Script gleich abgebrochen werden. Als nächstes wird geprüft, ob der Parameterwert für die Sortierrichtung entweder asc (für aufsteigend) oder desc (für absteigend) lautet. Abschließend wird der Aufruf des Scripts zusammengesetzt, und die Ajax-Kernel-Funktion doHTTPRequest() wird aufgerufen. Der Parameter outputId, der den id-Namen des Ausgabeelements enthält, wird an diese Funktion weitergereicht. Der Ajax-Kernel besorgt den Aufruf des Scripts userSort.php und gibt die fertig sortierte Tabelle an der gewünschten Stelle im Dokument aus.

Alle Quelltexte dieses Beispiels einschließlich komplettem HTML-Dokument und MySQL-create-Daten können Sie als ZIP-Datei downloaden.


Donnerstag, 28. Juni 2007

Tutorial: Ajax (7)

siehe auch:
(1): Was ist Ajax?
(2): Warum heißt Ajax so? Wo kann ich Ajax in Aktion sehen?
(3): Worin besteht die Ajax-Schnittstelle? Wie wird Ajax standardisiert?
(4): Welche Nachteile hat Ajax? Wie sicher ist Ajax?
(5): Ein einfacher Ajax-Kernel
(6): Eigenschaften und Methoden des XMLHTTPRequest-Objekts


Ajax-Beispiel: Formularüberprüfung

Einer der klassischen Anwendungsfälle für JavaScript ist das Prüfen von Anwendereingaben in Formularen, bevor das Formular abgesendet wird. So war es beispielsweise immer schon möglich, mittels JavaScript zu prüfen, ob in einem Feld ein numerischer Wert, eine Mailadresse mit gültigem Format oder ein realistisches Datum eingegeben wurde. Nicht möglich war es jedoch zu prüfen, ob etwa ein eingegebener Name, der in einer Datenbanktabelle auf dem Server eindeutig sein soll, dort bereits vorhanden ist oder nicht. Ajax kann diesen Fall lösen, und unser erstes kleines Beispiel zeigt wie.

HTML-Formular

Nehmen wir an, in einem Content Management System (CMS) können Anwender Templates anlegen und verwalten. Jedes Template erhält einen Namen, unter dem es auflistbar ist – beispielsweise beim Erstellen von Webseiten. Der Template-Name muss deshalb eindeutig sein. Im HTML-Formular notieren wir dazu neben dem Eingabefeld für den Template-Namen eine Schaltfläche mit der Beschriftung Prüfen:

<div><input type="text" name="template_name" id="template_name" 
       class="text" style="width:390px" accesskey="n"> 
<input type="button" name="check_name" 
       class="button" style="width: 96px" value="Prüfen" 
       onclick="ajaxCheckDBValue('templates', 'name', 'string', 
                document.getElementById('template_name').value, 
                'check_result', 0)"></div>
<div id="check_result"></div>

Den Rest des gedachten HTML-Formulars sparen wir uns, da er nichts zur Sache beiträgt. Das erste input-Element definiert ein einzeiliges Eingabefeld, das unter anderem ein id-Attribut mit dem Wert template_name erhält. Das zweite input-Element definiert die Schaltfläche mit value="Prüfen" (Beschriftungstext). Damit die Schaltfläche beim Anklicken etwas tut, erhält das Element einen Event-Handler onclick=. Der JavaScript-Code, der diesem Event-Handler zugewiesen wird, ist der Aufruf einer JavaScript-Funktion namens ajaxCheckDBValue(). Dieser Funktion werden folgende Parameter übergeben:

  • 'templates' ist der Name einer Datenbanktabelle, in der die Namen von Templates gespeichert werden.
  • 'name' ist der Name der Tabellenspalte, in der die Namen von Templates gespeichert werden.
  • 'string' markiert die Art, wie die Daten in MySQL zu behandeln sind. Als mögliche Angaben benötigt dieser Parameter nur die möglichen Werte 'string' und 'num'.
  • document.getElementById('template_name').value referenziert den aktuellen Eingabewert des ersten input-Elements.
  • 'check_result' referenziert das div-Element, das unterhalb der beiden input-Elemente notiert ist. Dort soll das Ergebnis der Prüfung ausgegeben werden.
  • 0 bedeutet: es soll kein Datensatz von der Gegenprüfung ausgeschlossen werden. Was dieser Wert genau bedeutet, werden wir noch genauer beschreiben.

JavaScript zur Steuerung

In dem HTML-Dokument mit dem zuvor beschriebenen Formularausschnitt muss in jedem Fall unser Ajax-Kernel (siehe (5): Ein einfacher Ajax-Kernel) eingebunden werden. Angenommen, wir haben den Code des Kernels in einer Datei namens ajax.js gespeichert, die im gleichen Verzeichnis liegt, kann diese Datei wie üblich zwischen <head> und </head> so eingebunden werden:

<script type="text/javascript" src="ajax.js"></script>

Der Einfachheit halber notieren wir die Funktion ajaxCheckDBValue() ebenfalls in der Datei ajax.js — beispielsweise unterhalb der beiden Funktionen des Kernels. Die Funktion besteht aus folgendem Code:

function ajaxCheckDBValue(DBTable, DBField, type, fieldValue, outputId, exclDBId) {
   if(!document.getElementById)
      return;
   if(fieldValue == "") {
 document.getElementById(output_id).innerHTML = 
         "<span class=\"errortext\">Keinen Wert angegeben!</span>";
 return;
   }
   scriptUrl = "http://localhost/ajax-test/checkDBValue.php";
   paramStr = "?table=" + DBTable + "&field=" + DBField + "&type=" + 
               type + "&value=" + encodeURIComponent(value) +
               "&excldbid=" + exclDBId;
   doHttpRequest(scriptUrl + paramStr, outputId);
}

Die Funktion erwartet fünf Parameter, die wir zuvor beim Aufruf der Funktion im HTML-Code bereits an einem Beispiel kennengelernt haben.

Zunächst überprüft die Funktion mit if(!document.getElementById), ob überhaupt die DOM-Schnittstelle zur Verfügung steht. Anschließend prüft sie, ob der übergebene Feldwert (Parameter fieldValue) überhaupt einen Wert hat. Falls der Benutzer in unserem Beispiel auf die Schaltfläche Prüfen klickt, ohne in dem Eingabefeld einen Wert eingegeben zu haben, können wir uns die Ajax-Verbindung nämlich sparen. In diesem Fall reagiert die Funktion mit der Ausgabe des Fehlers Keinen Wert angegeben. Die Ausgabe erfolgt dynamisch innerhalb des Formulars an der Stelle, an der auch die Ajax-Meldungen erscheinen sollen.

Sind diese Prüfunden überstanden, wird der Aufruf der Zentralfunktion doHttpRequest() des Ajax-Kernels vorbereitet (siehe siehe (5): Ein einfacher Ajax-Kernel). Der Funktion wird die URL eines serverseitigen Scripts übergeben sowie der id-Attributwert des HTML-Elements (outputId), in dem die serverseitig erzeugte Ergebnismeldung ausgegeben werden soll. Die URL des serverseitigen Scripts setzen wir zusammen aus der vollständigen HTTP-Adresse der Scriptdatei, gespeichert in scriptUrl, sowie einem GET-Parameterstring, gespeichert in paramStr. Über die GET-Parameter versorgen wir das serverseitige Script, ein PHP-Script, mit den nötigen Input-Daten. Alle Parameter, die unsere Funktion ajaxCheckDBValue() selbst erhalten hat, werden dabei an das serverseitige Script weitergegeben. Da der Feldwert, also die vom Anwender eingegebenen Daten (gespeichert in fieldValue) auch Zeichen enthalten können, die in einer URL-Adresse besondere Bedeutung haben, wenden wir die JavaScript-Standardfunktion encodeURIComponent() auf den Feldwert an. So wird der Feldwert URL-gerecht kodiert.

Zum Schluss wird die Ajax-Kernel-Funktion doHTTPRequest() mit den vorbereiteten Daten aufgerufen. Mehr ist nicht nötig. Die Ergebnismeldung wird vom serverseitigen Script erzeugt, und die Ajax-Kernel-Funktion sorgt dafür, dass sie an der gewünschten Stelle (nämlich im HTML-Element mit id-Attribut, das in outputId gespeichert ist) ausgegeben werden.

Serverseitige Verarbeitung

Wir nehmen für unser Beispiel an, dass es auf dem Server eine MySQL-Datenbank mit dem Namen cms gibt, zu der eine Tabelle namens templates gehört. In dieser Tabelle seien bislang folgende Daten gespeichert:

 +----+-------------+
 | id | name        |
 +----+-------------+
 |  1 | einspaltig  |
 |  2 | zweispaltig |
 |  3 | dreispaltig |
 +----+-------------+

Die id-Spalte speichert Autoincrement-Werte, wie sie in Datenbanktabellen häufig verwendet werden. In der Spalte name werden Template-Namen gespeichert. Diese Namen sollen tabellenweit eindeutig sein.

Unser serverseitiges PHP-Script checkDBValue.php, das in der Ajax-JavaScript-Funktion ajaxCheckDBValue() aufgerufen wird, hat also die Aufgabe, zu prüfen, ob der übergebene Wert, den der Benutzer im Feld eingegeben hat, in der Spalte name bereits vorhanden ist oder nicht.

Das PHP-Script hat in unserem Beispiel folgenden Code:

<?php

$dbh = mysql_connect("localhost", "dbuser", "dbpassword");
if(!$dbh)
   echo "<div>Keine Verbindung zum Datenbank-Management-System"; 
$sql = "USE cms";
$sqlResult = @mysql_query($sql, $dbh);
if(!$sqlResult)
   echo "<div>Keine Verbindung zur Datenbank</div>"; 
if(! isset($_GET['table']) or empty($_GET['table']))
   echo "<div>Keine Datenbanktabelle angegeben</div>";
if(! isset($_GET['field']) or empty($_GET['field']))
   echo "<div>Keinen Feldnamen angegeben</div>";
if(! isset($_GET['type']) or empty($_GET['type']))
   echo "<div>Keinen Feldtyp angegeben</div>";
if($_GET['type'] != "string" and $_GET['type'] != "num")
   echo "<div>Falschen Feldtyp angegeben</div>";
if(! isset($_GET['value']) or empty($_GET['value']))
   echo "<div>Keinen Wert angegeben</div>";
if(! isset($_GET['excldbid']))
   echo "<div>Keine Angabe zu auszuschließenden Datensätzen</div>";

if($_GET['type'] == "string")
   $fieldValue = "'" . $_GET['value'] . "'";
else
   $fieldValue = $_GET['value'];
$sql = "SELECT COUNT(*) AS count FROM " . $_GET['table'] ." WHERE " .
       $_GET['field'] . " = " . $fieldValue;
if((int) $_GET['excldbid'] > 0)
   $sql .= " AND id <> " . (int) $_GET['excldbid'];
$sqlResult = @mysql_query($sql, $dbh);
if(!$sqlResult) 
   echo "<div>Kein Datenbankergebnis</div>";
else {
   $res = mysql_fetch_array($sqlResult, MYSQL_ASSOC);
   if($res['count'] > 0)
       echo "<div><span class=\"warning\">Wert bereits vorhanden! 
             Bitte einen anderen Wert eingeben!</span></div>";
   else
       echo "<div>Der eingegebene Wert ist verfügbar</div>";
}

?>

Das Script baut zunächst mit der PHP-Funktion mysql_connect() eine Verbindung zum MySQL-System des Servers auf. Die dabei übergebenen Parameter sind natürlich in einer anderen Umgebung entsprechend anzupassen. Anschließend wird das SQL-Statement USE cms an MySQL gesendet, um die gewünschte Datenbank auszuwählen.

Daran anschließend überprüft das Script seine per GET-Parameter erhaltenen Daten. Fehlen übergebene Parameter oder enthalten sie keine oder ungültige Werte, wird mit echo eine entsprechende Fehlermeldung ausgegeben. Alles, was das Script übrigens mit echo ausgibt, wird von Ajax verarbeitet und wie definiert in der aktuell angezeigten Webseite dynamisch eingeblendet.

In der zweiten Hälfte baut das Script dann das SQL-Statement der eigentlichen Prüfabfrage zusammen. Mit SELECT count(*) ... wird ein Statement erzeugt, bei dem MySQL als Ergebnis nur die Anzahl der Datensätze (Tabellenzeilen) zurückliefert, auf die die formulierte WHERE-Klausel zutrifft.

Falls der GET-Parameter excldbid einen Wert größer 0 hat, wird die WHERE-Klausel dahingehend erweitert, dass der Datensatz, bei dem die Spalte id den Wert von excldbid hat, nicht mit berücksichtigt wird. Warum das? Ganz einfach: angenommen, das HTML-Formular, welches den Ajax-Request auslöst, ist ein Formular, in dem Daten eines bestehenden Templates geändert werden. In diesem Fall ist der vorbelegte Feldwert in der Datenbank natürlich schon vorhanden. Ein Klick auf Prüfen würde aus eben diesem Grund das für den Benutzer verwirrende Ergebnis Wert bereits vorhanden! Bitte einen anderen Wert eingeben! erzeugen. Um dies zu verhindern, kann beim Ändern eines bestehenden Datensatzes dessen id-Wert im Parameter excldbid übergeben werden.

Das PHP-Script kann seine Arbeit beenden, wenn das MySQL-Ergebnis vorliegt. Wurden mehr als 0 Datensätze gefunden, ist der Wert nicht mehr verfügbar. Entsprechende Meldungen werden mit echo ausgegeben und vom Ajax-JavaScript in die Webseite eingefügt.

Alle Quelltexte dieses Beispiels einschließlich komplettem HTML-Dokument und MySQL-create-Daten können Sie als ZIP-Datei downloaden.


Donnerstag, 7. Juni 2007

Tutorial: Ajax (6)

siehe auch:
(1): Was ist Ajax?
(2): Warum heißt Ajax so? Wo kann ich Ajax in Aktion sehen?
(3): Worin besteht die Ajax-Schnittstelle? Wie wird Ajax standardisiert?
(4): Welche Nachteile hat Ajax? Wie sicher ist Ajax?
(5): Ein einfacher Ajax-Kernel


Eigenschaften und Methoden des XMLHTTPRequest-Objekts

Das XML-HTTP-Objekt verfügt entsprechend der Spezifikation des W3-Konsortiums über folgende Eigenschaften und Methoden:

Eigenschaft: onreadystatechange

Genaugenommen ist dies ein Event-Handler, dem beliebiger JavaScript-Code zugeordnet werden kann, beispielsweise ein Funktionsaufruf: onreadystatechange = tuWas();

Das Ereignis dieses Event-Handler wird immer dann ausgelöst, wenn sich der Verbindungsstatus einer zuvor abgesetzten HTTP-Anfrage ändert. Bei jedem Auslösen des Ereignisses nimmt die Objekteigenschaft readyState einen anderen Wert an.

Eigenschaft: readyState

Diese Eigenschaft speichert den aktuellen Verbindungsstatus einer zuvor abgesetzten HTTP-Anfrage, und zwar in Form einer Zahl. Folgende Werte sind möglich:

0 (oder Konstante: UNINITIALIZED):
Diesen Wert hat die Eigenschaft, bevor die Methode open() aufgerufen wurde, die eine HTTP-Anfrage einleitet.

1 (oder Konstante: LOADING):
Dieser Wert bedeutet, dass die HTTP-Verbindung zum Webserver erfolgreich zustande kam. Diesen Wert hat die Eigenschaft, wenn open() eine Verbindung mit dem Webserver aufnehmen konnte, aber noch keine konkrete Anfrage mit send() gestartet wurde.

2 (oder Konstante: LOADED):
Dieser Wert bedeutet, dass der HTTP-Request vollständig übertragen wurde, und dass die Antwort-Header-Zeilen vom Webserver bereits vorliegen. Wenn readyState diesen Wert hat, können bereits die Methoden getAllResponseHeaders() und getResonseHeader() angewendet werden, um die Server-Antwort schon vor der Übertragung der Nutzdaten auszuwerten.

3 (oder Konstante: INTERACTIVE):
Diesen Wert hat die Eigenschaft, während die eigentlichen Nutzdaten vom Webserver empfangen werden. Die Eigenschaften responseText bzw. responseXML werden während dieses Zustands nach und nach mit den empfangenen Daten gefüllt.

4 (oder Konstante: COMPLETED):
Dies ist der Endzustand und bedeutet, dass die Server-Antwort komplett übertragen wurde.

Leider ist die Implementierung der Zustände von readyState in den verschiedenen Browsern nicht zuverlässig und einheitlich implementiert. So wertet beispielsweise der Opera-Browser nur die Zustände 3 und 4 aus. In der Praxis warten die meisten Ajax-Anwendungen deshalb bis readyState == 4, und beginnen dann mit der Verarbeitung der erhaltenen Antwortdaten.

Eigenschaft: responseText

Diese Eigenschaft enthält die vom Server gesendeten Nutzdaten als String. Was die Daten enthalten, hängt davon ab, was angefragt bzw. gesendet wurde. Bei Textdaten ist auch nichts weiter zur Zeichenkodierung festgelegt — all das sind Dinge, die das aufrufende JavaScript im Zusammenhang mit einem Aufruf vorher wissen muss.

Wenn es sich um Text oder HTML-formatierten Text handelt, werden empfangene Daten in der Regel über die DOM-0-Eigenschaft innerHTML in die aktuell angezeigte Webseite eingebaut.

Eigenschaft: responseXML

Diese Eigenschaft enthält nur dann einen konkreten Wert, wenn die Serverantwort explizit aus XML-Daten besteht. Gedacht ist diese Eigenschaft als Schnittstelle für das Document Object Model (DOM). Mit Hilfe der DOM-Schnittstelle von JavaScript lassen sich so empfangene Daten gezielt in die Dokumentstruktur der aktuell angezeigten Webseite einbauen.

Eigenschaft: status

Diese Eigenschaft speichert den HTTP-Statuscode einer Server-Antwort, sobald diese vorliegt. Nachfolgende Tabelle listet die wichtigsten HTTP-Statuscodes auf:

HTTP-Statuscode Erklärung
200 Der Server kann die angeforderten Daten wie gewünscht versenden. Dies ist der Normalfall, wenn keine Probleme auftauchen.
204 Der Server hat die Anfrage erhalten, sendet jedoch keine Daten zurück. Gut verwendbar ist dieser Status-Code bei Verwendung in serverseitigen Scripts, die zwar etwas auf dem Server erledigen, aber keinen neuen HTML-Code senden wollen.
301 Die angeforderten Daten befinden sich nicht mehr unter dem URI, sie wurden dauerhaft auf eine andere Adresse verschoben. In der Statusmeldung (Eigenschaft statusText) wird angegeben, unter welchem URI sich die Daten jetzt befinden.
302 Die angeforderten Daten wurden vorübergehend zu einem anderen URI verschoben. In der Statusmeldung (Eigenschaft statusText) wird angegeben, unter welcher Adresse sich die Daten derzeit befinden.
304 Die angeforderten Daten haben sich gegenüber einer früheren Anfrage nicht geändert und werden deshalb nicht erneut gesendet.
400 Die Anfrage enthält Syntaxfehler. Der Server kann die Anfrage deshalb nicht bearbeiten.
401 Die angeforderten Daten sind zugangsgeschützt. Der Server kann die Daten nur senden, wenn eine gültige Zugangskennung, bestehend aus Benutzername und Passwort, bei der Anfrage mit gesendet wird.
403 Der Server möchte die angeforderten Daten nicht herausgeben. Das passiert zum Beispiel, wenn der Zugriff auf die Ressource von dem IP-Adress-Bereich, aus dem die Anfrage kommt, in der Serverkonfiguration verboten wurde, die Ressource ganz und gar gesperrt wurde oder man versucht, ein Verzeichnislisting zu bekommen, dies jedoch in der Serverkonfiguration abgeschaltet wurde.
404 Der angeforderte URI existiert nicht.
500 Der Server kann die angeforderten Daten nicht senden, weil auf dem Server ein Fehler aufgetreten ist. Beispielsweise konnte das aufgerufene Script auf dem Server nicht gestartet oder korrekt ausgeführt werden.

Eigenschaft: statusText

Diese Eigenschaft ist nur im Zusammenhang mit der Eigenschaft status zu betrachten. Sie enthält die vom Webserver mitgelieferte Textmeldung zu einem Statuscode. In einigen Fällen (z.B. bei den Statuscodes 301 und 302) enthält die Meldung wichtige zusätzliche Angaben.

Methode: abort()

Mit dieser Methode wird eine laufende Kommunikation mit dem Webserver abgebrochen. Der Event-Handler onreadystatechange wird auf 0 zurückgesetzt. Die verwendete Instanz des XMLHTTPRequest-Objekts kann für eine neue Webserver-Anfrage genutzt werden. Sinnvoll ist der Einsatz dieser Methode beispielsweise, wenn der Anwender die Möglichkeit hat, eine Aktion, für die Ajax zum Einsatz kommt, mit Hilfe einer „Abbrechen“-Schaltfläche zu stoppen. Die Abbrechen-Schaltfläche kann in einem solchen Fall die abort()-Funktion starten.

Methode: getAllResponseHeaders()

Diese Methode ist aufrufbar, sobald der Server zumindest seinen Antwort-Header gesendet hat (die Eigenschaft readyState muss mindestens den Wert 2 haben). Sie liefert die gesamten Header-Felder der Server-Antwort als eine Zeichenkette zurück. Um bestimmte Header-Felder abzufragen, ist die Methode getResponseHeader() besser geeignet. Beispiel (httpRequest ist der Name der Objektinstanz des XMLHTTPRequest-Objekts):

httpRequest.getAllResponseHeaders();

erzeugt eine Rückgabe, die so ähnlich aussieht wie:

Date: Sun, 10 Jun 2007 04:58:38 GMT
Server: Apache/1.3.31 (Unix)
Keep-Alive: timeout=15, max=99
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/plain; charset=utf-8

Methode: getResponseHeader(name)

Diese Methode ist ebenso wie getAllResponseHeaders() aufrufbar, sobald der Server zumindest seinen Antwort-Header gesendet hat (die Eigenschaft readyState muss mindestens den Wert 2 haben). Im Parameter name muss die Bezeichnung eines HTTP-Header-Feldes übergeben werden. Die Methode liefert dann den zugehörigen Wert als Zeichenkette zurück, sofern das Feld im HTTP-Antwort-Header überhaupt vorkommt. Beispiel:

httpRequest.getResponseHeader("Content-Type");

erzeugt eine Rückgabe, die so ähnlich aussieht wie:

Content-Type: text/plain; charset=utf-8

Methode: open(method, url[, asyncFlag[, userName[, password]]])

Die open()-Methode öffnet eine HTTP-Verbindung zu einem Webserver. Dabei müssen mindestens die beiden Parameter method und url übergeben werden.

Der Parameter method bestimmt die Übertragungsmethode. Üblich sind die Angaben "get" und "post". Weitere mögliche HTTP-Methoden sind "put" und "head", die jedoch in der Praxis seltener verwendet werden. Die Standardmethode ist "get". Die Methode "post" wird dann verwendet, wenn das Ajax-Script selbst schon Nutzdaten an den Server senden will. Ein möglicher Anwendungsfall wären Formulardaten, die bereits während der Eingabe und vor dem Absenden des Formulars auf dem Server zwischengespeichert, überprüft oder anderweitig verarbeitet werden sollen.

Der Parameter url ist keine vollständige HTTP-Adresse, sondern nur eine Pfadangabe. Denn wie bereits erwähnt, kann ein Ajax-Script nur Adressen auf demjenigen Webserver aufrufen, von dem aus es selbst an den Browser übertragen wurde. In aller Regel handelt es sich bei der Adresse, die mit url übergeben wird, um ein für den Webserver ausführbares Script, also z.B. um ein PHP-Script oder um ein CGI-Script in Perl.

Wenn Sie für den Parameter asyncFlag explizit einen Wert übergeben wollen, müssen Sie true oder false übergeben. Mit true erzwingen Sie einen asynchronen Scriptablauf, und mit false einen synchronen Scriptablauf.
Ein asynchroner Scriptablauf bedeutet, dass JavaScript nicht wartet, bis die Antwort des Webservers vollständig übertragen wurde, sondern dass der Rest des JavaScripts sofort abgearbeitet wird. Bei einem synchronen Scriptablauf verhindert der Aufruf der Methode send() den weiteren Ablauf des JavaScripts so lange, bis die Serverantwort vollständig eingetroffen ist.
Der Default-Wert ist true, also ein asynchroner Scriptablauf. Der Vorteil davon ist, dass JavaScript seine Aufgaben erledigen kann und weitere Anwenderaktionen beispielsweise nicht blockiert sind. Dabei entsteht jedoch das Problem, dass die Daten des Webservers erst eintreffen, wenn das JavaScript bereits fertig durchgelaufen oder zumindest im Ablauf schon weiter ist. Aus diesem Grund wird bei asynchonem Scriptablauf eine sogenannte Callback-Funktion definiert, die dann aufgerufen wird, wenn die Serverantwort vorliegt. Der Event-Handler dafür ist onreadystatechange.

Die Parameter username und password sind nur dann von Bedeutung, wenn der Webserver für die über Ajax aufgerufene URL eine Identifizierung verlangt. Es ist jedoch nicht empfehlenswert, solche Inhalte über Ajax aufzurufen, da dann Benutzername und Passwort im JavaScript-Quelltext stehen, der für Web-Benutzer leicht einsehbar ist.

Methode: send([content])

Diese Methode sendet eine HTTP-Anfrage an den Webserver. Zuvor muss die Verbindung zum Webserver mit der Methode open() erfolgreich hergestellt worden sein. Wenn Sie als Anfragemethode get verwenden, übergeben Sie send() keinen Parameter. Wenn Sie dagegen post verwenden, müssen Sie send() eine Zeichenkette übergeben, welche die zu postenden Daten enthält. Diese Daten müssen in der Form www-form-urlencoded vorliegen, also so kodiert sein wie ein GET-Parameterstring (Felder durch & trennen, Feldname und Feldwert durch = trennen, www-form-url-eigene Zeichen hexadezimal kodieren — für letzteres stellt JavaScript die Funktion encodeUri() zur Verfügung).

Methode: setRequestHeader(name, value)

Mit dieser Methode können Sie der HTTP-Anfrage gewünschte HTTP-Header übergeben. So können Sie beispielsweise gewünschte Zeichensätze angeben — im Prinzip kann name alles sein, was in HTML an <meta http-equiv=... zugewiesen werden kann, und value alles, was im gleichen HTML-Tag content= zugewiesen werden kann.


Freitag, 18. Mai 2007

Tutorial: Ajax (5)

siehe auch:
(1): Was ist Ajax?
(2): Warum heißt Ajax so? Wo kann ich Ajax in Aktion sehen?
(3): Worin besteht die Ajax-Schnittstelle? Wie wird Ajax standardisiert?
(4): Welche Nachteile hat Ajax? Wie sicher ist Ajax?


Ein einfacher Ajax-Kernel

Die Ajax-Schnittstelle selbst ist vergleichsweise überschaubar. Das XML-HTTP-Objekt lässt sich, wie bereits beschrieben, mit einer kleinen Browserweiche zuverlässig in allen modernen Browsern initialisieren. Die Aufgabe des Objekts besteht darin, HTTP-Requests an den Webserver abzusetzen und nachfolgende HTTP-Responses vom Webserver zu empfangen. Es bietet sich daher an, diese Aufgabe in eine kleine, wiederverwendbare Code-Bibliothek (die wir den „Ajax-Kernel“ nennen wollen) zu packen.

Die Funktionen

Für unsere einfachen Beispiele und für viele Anwendungsfälle in der Praxis genügt der nachfolgend vorgestellte Ajax-Kernel. Je nach Aufgabenstellung können komplexere Varianten dieses Kernels erforderlich werden. Beispielsweise dann, wenn POST-Daten über die Ajax-Schnittstelle an den Webserver übertragen werden sollen (unser Beispiel-Kernel sendet nur GET-Requests).

Eine Möglichkeit besteht darin, den nachfolgenden Code in einer eigenen JavaScript-Datei zu speichern – nennen wir sie ajax.js:

var httpRequest = false;
var noResult = "Kein Ergebnis";

// ===================================

function doHttpRequest(url, outputId) {
   httpRequest = false;
   if(window.XMLHttpRequest)  // Mozilla, Safari,...
       httpRequest = new XMLHttpRequest();
   else if(window.ActiveXObject) { // IE
       try {
           httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
    }
       catch (e) {
           try {
               httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
     }
           catch (e) {}
       }
   }
   if(!httpRequest) 
      return false;
   httpRequest.onreadystatechange = function() {
      if(httpRequest.readyState == 4) {
         if(httpRequest.status == 200) 
            handleHttpResponse(httpRequest.responseText, outputId);
       else
          return false;
         }
    else
       return false;
   } 
   httpRequest.open('get', url, true);
   httpRequest.send(null);
}


function handleHttpResponse(content, outputId) {
   if(!document.getElementById)
      return false;
   if(!document.getElementById(outputId))
   return false;
   if(content == "FALSE")
      document.getElementById(outputId).innerHTML = noResult;
   else
      document.getElementById(outputId).innerHTML = content;
} 

Um die Funktionsweise des XML-HTTP-Objekts zu verstehen, ist es allerdings wichtig, entscheidende Details aus diesem Code zu verstehen.

Der Code besteht aus zwei Funktionen:

  • Die Funktion doHttpRequest() ist die zentrale Steuerfunktion. Sie wird von anderem JavaScript-Code, der den Ajax-Kernel verwenden möchte, aufgerufen.
  • Die Funktion handleHttpResponse() ist eine interne Funktion, die nur von doHttpRequest() aufgerufen wird.

Zu Beginn des Ajax-Kernels werden ferner zwei globale Variablen definiert:

  • Die Variable httpRequest speichert eine Instanz des XML-HTTP-Objekts. Sie wird mit dem booleschen Wert false initialisiert.
  • Die Variable noResult wird mit einem Text initialisiert, der ausgegeben werden soll, wenn eine Ajax-Operation keine Daten vom Server erhält.

Die Funktion doHTTPRequest()

Die Funktion doHTTPRequest() erwartet zwei Parameter:

  • url ist die vollständige URL-Adresse eines Scripts auf dem Webserver, das über Ajax aufgerufen werden soll. Dieses Script — es kann sich beispielsweise um ein PHP-Script handeln — kann beispielsweise Daten aus einer Datenbank auslesen, in HTML-Form aufbereiten und diesen aufbereiteten HTML-Code zurückgeben.
  • output_id ist der id-Attributwert eines HTML-Elements im aktuell im Browser angezeigten HTML-Dokument. In dieses Element wird der HTML-Code, den das mit url bezeichnete Script erzeugt, dynamisch eingebaut — und genau dadurch entsteht der Effekt, den Ajax ausmacht.

Den ersten Teil der Funktion doHTTPRequest() kennen Sie bereits. Mittels einer geeigneten Browser-Weiche wird eine Instanz des XML-HTTP-Objekts erzeugt, was praktisch in allen modernen Browsern gelingt.

Der neue Teil beginnt mit httpRequest.onreadystatechange = function(). Allein dieses Konstrukt ist jedoch sehr erklärungsbedürftig.

onreadystatechange sieht aus wie eine Eigenschaft des XML-HTTP-Objekts. Das Präfix on... signalisiert jedoch, dass es sich um einen Event-Handler handelt, also um ein Ereignis, bei dessen Eintreffen etwas Bestimmtes geschehen soll. Deshalb wird dieser Eigenschaft auch kein einfacher Wert wie eine Zahl oder eine Zeichenkette zugewiesen, sondern eine Prozedur, die bei Eintreffen des Ereignisses ausgeführt werden soll. Die Prozedur wird eingeschlossen in:

   httpRequest.onreadystatechange = function() {
      // hier der Code der Prozedur
   }

Mit function() wird eine unbenannte Funktion aufgerufen, die man sich als eine mehrfach aufrufbare Subroutine innerhalb der Funktion doHTTPRequest() vorstellen muss. In unserem Fall lautet der Code innerhalb der Prozedur:

      if(httpRequest.readyState == 4) {
         if(httpRequest.status == 200) 
            handleHttpResponse(httpRequest.responseText, outputId);
       else
          return false;
         }
    else
       return false;

readyState ist eine „echte“ Eigenschaft des XML-HTTP-Objekts. In der Eigenschaft wird in Form eines Integer-Werts gespeichert, in welcher Phase sich eine aktuelle, vom XML-HTTP-Objekt gestartete HTTP-Kommunikation befindet. Mögliche Werte sind 0 bis 4. Eine vollständige HTTP-Kommunikation durchläuft nacheinander alle fünf Werte:
0 ist einfach der Anfangswert.
1 bedeutet, dass die HTTP-Verbindung zum Webserver erfolgreich zustande kam.
2 bedeutet, dass der HTTP-Request vollständig übertragen wurde.
3 bedeutet, dass die HTTP-Header der Server-Antwort empfangen wurden.
4 bedeutet, dass die Server-Antwort komplett übertragen wurde.

Der Event-Handler onreadystatechange bewirkt, dass bei jeder Änderung des Werts von readyState die Prozedur, die onreadystatechange zugewiesen ist, erneut ausgeführt wird. Innerhalb der Prozedur könnten wir also auf jede genannte Phase der HTTP-Kommunikation mit Script-Code reagieren. Im Beispiel reagieren wir jedoch nur auf die letzte Phase, nämlich mit if(httpRequest.readyState == 4). Die übrigen Phasen werden durch durch else return false ignoriert.

Wenn readyState den Wert 4 hat, ist also die HTTP-Kommunikation abgeschlossen und der Webserver hat seine Antwort auf eine Anfrage gesendet. Um die Antwort auszuwerten, ist es zweckmäßig, zunächst den HTTP-Statuscode der Server-Antwort auszulesen. Dieser ist in der Eigenschaft status des XML-HTTP-Objekts gespeichert. In unserem Beispiel erwarten wir für den „Gutfall“ den HTTP-Status-Code 200. Dieser Code bedeutet, dass der Server den HTTP-Request erfolgreich bearbeiten konnte und die angeforderten Daten senden konnte.

Auf den HTTP-Status-Code 200 reagieren wir mit einem Aufruf der zweiten Funktion unseres Ajax-Kernels: handleHTTPResponse(), auf die wir weiter unten noch näher eingehen werden. Der Funktion werden zwei Parameter übergeben, nämlich die vom Webserver erhaltenen Nutzdaten, sowie den id-Attributwert eines Elements im aktuell angezeigten HTML-Dokument, innerhalb dessen die Daten ausgegeben werden sollen. Was letzteres betrifft, so reichen wir den Parameter outputId einfach durch.

Die eigentlichen Daten übergeben wir mit einer weiteren Eigenschaft des XML-HTTP-Objekts, nämlich httpRequest.responseText. Diese speichert die vom Web­server erhaltenen Nutzdaten als normale Zeichenkette. Wenn also beispielsweise ein über Ajax aufgerufenes PHP-Script auf dem Server HTML-Code generiert und zurückgibt, ist in der Objekteigenschaft responseText dieser HTML-Code enthalten.

Die beiden letzten Anweisungen der Funktion doHttpRequest() sind einigermaßen verständlich. Mit httpRequest.open('get', url, true) wird die Methode open() des XML-HTTP-Objekts aufgerufen. Diese Methode setzt einen HTTP-Request an den Server ab. Als erster Parameter wird die Request-Methode angegeben. In unserem Fall ist das die GET-Methode. Der zweite Parameter übergibt die URL-Adresse, an die der HTTP-Request gehen soll. Der dritte Parameter ist ein true-false-Wert. Wenn auf true gesetzt (was auch die Default-Einstellung ist), wird die JavaScript-Funktion weiter ausgeführt, auch wenn noch keine Server-Antwort vorliegt. Wenn auf false gesetzt, wartet JavaScript mit der Ausführung der weiteren Anweisungen so lange, bis die Server-Antwort vorliegt. Die Funktion ist also in unserem Fall eigentlich längst beendet, wenn die Antwortdaten vom Webserver eintreffen. Um sie dennoch abzufangen, haben wir zuvor die Ereignisbehandlung für onreadystatechange definiert.

Mit httpRequest.send(null) wird dem Server mitgeteilt, dass außer dem Request selber kein Daten an den Server gesendet werden. Falls dem aufzurufenden Script auf dem Server Daten übergeben werden sollen, können Sie anstelle von null einen Query-String übergeben, der nach den dafür üblichen Regeln aufgebaut ist, also z.B.:

httpRequest.send("name=value&another_name=another_value");

Die Funktion handleHttpResponse()

Die Funktion handleHttpResponse() erwartet zwei Parameter:

  • content ist eine beliebige Zeichenkette, die Text bzw. HTML-Code enthalten sollte.
  • output_id ist der id-Attributwert eines HTML-Elements im aktuell im Browser angezeigten HTML-Dokument. In dieses Element wird der HTML-Code, der mit content übergeben wird, dynamisch eingebaut.

Die Funktion dient wie schon erwähnt nur als Subroutine für die Ajax-Kernel-Hauptfunktion doHTTPRequest(). Beim Parameter content besteht zusätzlich die Möglichkeit, anstelle einer Zeichenkette den Booleschen Wert false zu übergeben. In diesem Fall setzt die Funktion als Inhalt des mit outputId bezeichneten Elements den Inhalt der globalen Variablen noResult ein, die zu Beginn des Kernel-Scripts initialisiert wurde.


Sonntag, 6. Mai 2007

Tutorial: Ajax (4)

siehe auch:
(1): Was ist Ajax?
(2): Warum heißt Ajax so? Wo kann ich Ajax in Aktion sehen?
(3): Worin besteht die Ajax-Schnittstelle? Wie wird Ajax standardisiert?


Welche Nachteile hat Ajax?

Bei allem Mehrwert, den Ajax dem Benutzer einer Webanwendung bieten kann, sollen jedoch die Nachteile nicht verschwiegen werden. Folgende Probleme treten im Zusammenhang mit Ajax auf:

  • Die Grenzen zwischen URL-Adressen und Seitenzuständen verschwimmen:
    Eine Webseite zeichnet sich dadurch aus, dass sie eine feste URL-Adresse hat. Wenn eine Webseite intensiv mit Ajax arbeitet, kann es jedoch passieren, dass der Benutzer lange Zeit gar keine neue Seite mit eigener URL-Adresse nachfordert. Stattdessen setzt ihm JavaScript neue Inhalte und Seitenzustände direkt in den bestehenden HTML-Code ein. Da so erzeugte Inhalte und Seitenzustände aber keine eigene URL-Adresse haben, lassen sie sich nicht als Bookmark/Favorit abspreichern, und andere Webseiten können keine direkten Links („Deeplinks“) auf solche Inhalte setzen. Die Vor- und Zurück-Funktion des Browsers, die das Bewegen in der Historie besuchter Seiten ermöglicht, funktioniert ebenfalls nicht mehr wie erwartet. Denn diese Funktion springt immer nur zum Anfangszustand einer Seite. Auch Suchmaschinen-Robots werden in aller Regel nur den Anfangszustand einer Seite indexieren und weitere, über Ajax ermittelbare Seiteninhalte ignorieren.
  • Ajax ist nur mit aktiviertem JavaScript verfügbar:
    Per Voreinstellung ist JavaScript in allen modernen Browsern aktiviert. Weil JavaScript jedoch nach dem Boom der Anfangsjahre etwas in Verruf geraten war, nutzten viele Anwender die Möglichkeit, JavaScript zu deaktivieren. Viele nervige Popup-Fenster, hinderliche Effekten und sonstiges Blendwerk ließen sich auf diese Weise unterdrücken. Wer das auch heute noch tut, wird von Inhalten, die nur über Ajax ermittelt werden, erst gar nichts sehen. Gleiches gilt für Anwender, die aus technischen oder körperlichen Gründen Browser-Lösungen in reinen Textumgebungen verwenden. Solche Browser unterstützen in aller Regel auch kein JavaScript. Inhalte, die nur über Ajax ermittelbar sind, bleiben also unzugänglich.
  • Die Server-Belastung kann sehr hoch werden:
    Wenn Anwenderaktionen wie Mausklicks oder gar Mouseover-Ereignisse jedesmal eine HTTP-Kommunikation auslösen, entsteht viel zusätzliche HTTP-Kommunikation zwischen Client und Server. Der Client, also der Browser des Anwenders, wird dadurch nicht nennenswert belastet, um so mehr jedoch der Webserver, der möglicherweise für viele gleichzeitige Benutzer die Ajax-bedingte HTTP-Kommunikation abwickeln muss. Eine Ajax-intensive Webanwendung, die von vielen Besuchern gleichzeitig genutzt wird, kann einen Webserver durchaus in die Knie zwingen. Das gilt insbesondere für Anwendungen, bei denen eigentlich ein Server-Push, also eine vom Server gestartete Kommunikation sinnvoll wäre, wie etwa bei einem Chat. Da es im HTTP-Protokoll jedoch keinen Server-Push gibt, muss der Client, also JavaScript, in kurzen Zeitintervallen immer wieder beim Server nachfragen.
  • Wartezeit bis HTTP-Antwort kann Anwendungen lahm erscheinen lassen:
    Wenn ein Anwender in seinem Browser eine neue Webseite aufruft, weiß er, dass es einen oder ein paar Momente dauern kann, bis alle Daten angezeigt werden können. Eine Webanwendung, die mit Ajax Daten „nachlädt“, muss ebenfalls einen oder ein paar Momente auf Antwort warten. Ein Anwender, der nichts von Ajax weiß (und welcher Normalanwender muss das schon wissen?), bekommt in solchen Fällen den Eindruck, als ob die Webanwendung sehr zäh reagiert. Er klickt auf einen Button und muss möglicherweise mehrere Sekunden warten, bis das Ergebnis des ausgelösten Ereignisses sichtbar wird. Dies widerspricht seiner Erfahrung, wonach einmal geladene Webseiten sich im Speicher des eigenen Browsers befinden und sehr schnell reagieren.

Einige dieser Probleme sind allerdings durchaus lösbar. Eine Webanwendung kann beispielsweise so konzipiert werden, um GET-Parameter zu erkennen, über die sich direkt Inhalte und Seitenzustände ansprechen lassen, die sonst erst durch Ajax-Aktionen zustande kommen. Bei Wartezeiten, verursacht durch Ajax-HTTP-Anforderungen im Hintergrund, kann dem Anwender ein bekanntes Warte-Symbol (z.B. eine Sanduhr) angezeigt werden.

Was die Verfügbarkeit von JavaScript betrifft, so müssen Webentwickler eine Grundsatzentscheidung treffen. Entweder man macht die Aktivierung von JavaScript einfach zur Bedingung, oder man versucht, Ajax nur für Mehrwert-Funktionen eingesetzt werden (z.B. Tabellensortierung), wobei eine Grundfunktionionalität (z.B. Tabelle, die nicht sortierbar ist) gewährleistet ist. Vor allem Websites, die den Charakter einer Web­anwendung haben, mit der Benutzer etwas bearbeiten können, haben durchaus das Recht, die Aktivierung von JavaScript zur Bedingung zu machen. Bei gewöhnlichen Webseiten ist dagegen eher die Lösung angebracht, Ajax nur für Mehrwert-Funktionalität einzusetzen.

Wie sicher ist Ajax?

JavaScripts mit Ajax stoßen Scripts an, die auf einem Webserver laufen, also beispielsweise PHP-Scripts. Das serverseitige Script muss sich dazu in der „Document Root“ des Webservers befinden, also in jenem Verzeichnisbereich, der über URLs adressierbar ist. Das klingt gefährlich. Doch letztlich passiert dabei nichts anderes, als wenn ein Anwender die URL-Adresse eines solchen Scripts auf dem Webserver selbst in die Adresszeile seines Browsers eingibt, oder wenn er sich selbst ein HTML-Formular bastelt, das ein solches Script beim Absenden aufruft und ihm Daten übermittelt. Es liegt in all diesen Fällen an der serverseitigen Programmierung, dafür zu sorgen, dass über GET-Parameter oder POST-Daten keine ungewollten oder schädlichen Aktionen auf dem Server ausgelöst werden.

Das Sicherheitskonzept von Ajax geht jedoch noch einen Schritt weiter. Es sieht vor, dass ein JavaScript, welches das XML-HTTP-Objekt einsetzt, vom gleichen Webserver kommen muss wie das serverseitige Script, das es aufruft. Es ist also nicht möglich, durch ein selbstgebasteltes JavaScript via Ajax ein serverseitiges Script auf einem beliebigen Webserver zu starten.

Ajax-Fehlermeldung im Firefox-Browser
Fehlermeldung in der JavaScript-Konsole des Firefox-Browsers beim Versuch eines JavaScripts, einen HTTP-Request an eine fremde Domain zu senden

Im Klartext bedeutet das: Ein Benutzer muss in seinem Browser zunächst eine Webseite auf einem Webserver aufrufen. Diese Webseite enthält ein JavaScript mit Ajax-Code. Das Script wird zusammen mit der Webseite an den Browser des Anwenders übertragen. Das Script mit dem Ajax-Code kann nun HTTP-Requests absenden, jedoch nur zu dem Webserver (genauer: zu der Domain), von welcher die Webseite mitsamt dem Script an den Browser übertragen wurde.

Als Website-Betreiber müssen Sie entweder ein eigenes JavaScript mit ausliefern, das serverseitige Scripts auf der eigenen Domain aufrufen kann. Oder Sie binden ein JavaScript von einer fremden Domain ein, das jedoch nur serverseitige Scripts auf der Domain aufrufen kann, von der es ausgeliefert wird.

Wie sicher eine Ajax-basierte Web-Umgebung ist, bleibt also daran hängen, wie sicher die serverseitige Programmierung ist, welche Ajax-Anfragen verarbeitet. Ein PHP-Script etwa, das ungeprüft Daten, die aus GET- oder POST-Parametern stammen, in ein MySQL-Statement einbaut und die Daten in eine Datenbank schreibt, stellt ein hohes Sicherheitsrisiko dar. Dieses Risiko kann jedoch ebensowenig der Ajax-Schnittstelle angelastet werden wie der Programmiersprache PHP. Es liegt allein an der Sorgfalt der serverseitigen Programmierung, mit Input-Daten so umzugehen, dass daraus keine Gefahr entstehen kann.


Samstag, 28. April 2007

Tutorial: Ajax (3)

siehe auch:
(1): Was ist Ajax?
(2): Warum heißt Ajax so? Wo kann ich Ajax in Aktion sehen?


Worin besteht die Ajax-Schnittstelle?

Die Ajax-Schnittstelle besteht in einem speziellen JavaScript-Objekt, das HTTP-Requests absetzen und HTTP-Responses empfangen kann. Nun gehört ein solches Objekt nicht seit jeher zum Umfang von JavaScript, und deshalb stellt sich natürlich die Frage: wie und wo ist es implementiert, und welcher Browser kennt es?

Die Entwicklungen eines entsprechenden Script-Objekts gehen auf Microsoft zurück. Bereits 1997 verfügte der damalige MS Internet Explorer 4.0 über eine „Remote-Scripting-Komponente“, die allerdings nur mit dem hauseigenen Webserver Exchange funktionierte. Seit Produktversion 5.0 (1999) lässt sich im Internet Explorer ein XML-HTTP-Objekt in Form einer ActiveX-Komponente ansprechen. Seit Version 7.0 kennt der Internet Explorer ebenso wie alle übrigen heute verbreiteten Browser, also etwa Firefox, Safari oder Opera, ein ActiveX-unabhängiges XML-HTTP-Objekt.

Folgende Browserweiche genügt, um die Ajax-Schnittstelle in allen heute verbreiteten Browsern zu initialisieren:

var httpRequest = false;
if(window.XMLHttpRequest)  // Mozilla, Safari, Opera, MS IE 7, ...
   httpRequest = new XMLHttpRequest();
else if(window.ActiveXObject) { // MS IE 5, 6
   try {
      httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
   }
   catch (e) {
      try {
         httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
      }
      catch (e) {}
   }
}

Die Variable httpRequest soll das XML-HTTP-Objekt speichern. Über sie sind nach erfolgreicher Initialisierung Zugriffe auf Eigenschaften und Methoden des XML-HTTP-Objekts möglich. Zunächst wird die Variable mit dem Wert false initialisiert. Wenn ein XML-HTTP-Objekt erfolgreich initialisiert werden kann, ändert sich dieser Anfangswert.

Für alle modernen Browser genügt die Abfrage if(window.XMLHttpRequest). Damit wird geprüft, ob das XML-HTTP-Objekt im JavaScript-Interpreter verfügbar ist. Wenn ja, wird mit httpRequest = new XMLHttpRequest(); eine Instanz des Objekts in der zuvor erwähnten Variable httpRequest gespeichert.

Für das ActivX-basierte XML-HTTP-Objekt früherer Internet-Explorer-Versionen ist die Objektinitialisierung etwas komplexer. Mit if(window.ActiveXObject) wird zunächst herausgefunden, ob der Browser ein ActivXObject kennt, was ihn einigermaßen zuverlässig als Internet Explorer ausweist. Da es von Microsofts XML-HTTP-Objekt zwei Versionen gibt, wird auf beide Versionen geprüft. Zunächst wird getestet, ob die neuere Version ("Msxml2.XMLHTTP") verfügbar ist. Wenn nicht, wird versucht, die ältere Version ("Microsoft.XMLHTTP") anzusprechen. All diese Anfragen werden in try-catch-Statements eingebunden, um Laufzeitfehler zu vermeiden.

Die gute Nachricht lautet: es sind keine weiteren Verrenkungen für einzelne Browser erforderlich. Hat die Variable httpRequest ein XML-HTTP-Objekt gespeichert, kann fortan für alle Browser gleich programmiert werden, da das Objekt selbst, also seine Eigenschaften und Methoden, in allen Browsern gleich implementiert sind.

Wie wird Ajax standardisiert?

Die Entwicklung des XML-HTTP-Objekts verlief zunächst weitgehend ungesteuert. Mittlerweile hat sich jedoch das W3-Konsortium der Sache angenommen. Die aktuelle Spezifikation des XMLHTTPRequest-Objekts, wie es im offiziellen Wortlaut heißt, ist unter folgender Adresse zu finden:

http://www.w3.org/TR/XMLHttpRequest/

Derzeit (Stand: April 2007) ist dort noch keine Empfehlung (Recommendation) zu finden, sondern „nur“ eine Working Draft, also ein Arbeitsentwurf. Da das W3-Konsortium jedoch in diesem Fall eigentlich nur sanktioniert, was längst realisiert ist und genutzt wird, ist in der Spezifikation nicht mehr mit dramatischen Änderungen zu rechnen.

Der Einsatz von Ajax ist also keine halbseidene, proprietäre Angelegenheit mehr, sondern darf sich mittlerweile auf die Normierungshoheit des W3-Konsortiums berufen.


Sonntag, 15. April 2007

Tutorial: Ajax (2)

siehe auch:
(1): Was ist Ajax?


Warum heißt Ajax so?

Das Akronym Ajax steht für „Asynchronous JavaScript and XML“. Mit „asynchron“ ist in diesem Zusammenhang gemeint, dass eine HTTP-Kommuniktation zwischen Browser und Webserver auch ohne Anfordern einer komplett neuen Seite stattfinden kann, also während eine Webseite im Browser angezeigt wird — ausgelöst etwa durch Anwenderereignisse wie das Anklicken eines Elements.

Die Erwähnung von XML rührt daher, dass die Ajax-Technologie eng verknüpft ist mit dem Einsatz des vom W3-Konsortium standardisierten Document Object Models (DOM). Denn Inhalte, die JavaScript via Ajax-Schnittstelle vom Webserver anfordert, sollen in aller Regel dynamisch in eine bereits angezeigte Webseite eingebaut werden. In den meisten Praxis-Fällen erhält ein JavaScript vom Webserver einfach eine Portion HTML-Code, der dann mit der nicht ganz DOM-konformen, aber sehr beliebten Eigenschaft innerHTML in ein vorhandenes HTML-Element der angezeigten Webseite eingefügt wird.

Wer strenger DOM-konform arbeiten möchte, hat jedoch auch die Möglichkeit, sowohl in JavaScript als auch server-seitig mit DOM-Objekten zu arbeiten. Die JavaScript-Interpreter moderner Browser unterstützen das DOM zumindest so ausreichend, dass es sich sinnvoll einsetzen lässt. Serverseitig müssen Scripts, welche die Daten erzeugen, Wege finden, anstelle von HTML-Code in Textform DOM-Objektdaten zu erzeugen. In Programmiersprachen wie PHP gibt es dafür entsprechende Funktionsbibliotheken.

Dass in der Praxis viel häufiger mit textbasierten HTML-Code-Portionen und Einfüge-Operationen wie innerHTML gearbeitet wird, liegt auch daran, dass diese Form sowohl server- als auch client-seitig viel anspruchsloser und deshalb in aller Regel erheblich schneller ist. In den Praxisbeispielen dieses Tutorials werden wir uns der Einfachheit halber ebenfalls auf diese Variante beschränken.

Wo kann ich Ajax in Aktion sehen?

Ajax ist meistens dann im Spiel, wenn eine Website sich plötzlich so verhält, wie man es von leistungsstarken Desktop-Anwendungen gewohnt ist.

Beispiel 1: Google-Service Google Suggest:

http://www.google.com/webhp?complete=1&hl=en

Google Suggest Tippen Sie in das Suchfeld langsam etwas ein, etwa Ihren Vornamen. Nach jedem eingegebenen Zeichen erscheint eine Dropdown-Liste mit Vorschlägen für mögliche Suchausdrücke. Nach dem ersten Zeichen wird die Auswahl in der Regel noch sehr sinnlos sein, doch zwischen dem vierten bis zehnten Zeichen lässt sich der gewünschte Suchausdruk in aller Regel so weit eingrenzen, dass etwas Gewünschtes in der Liste dabei ist. Interessant bei der Vorschau ist vor allem die Angabe der Suchtrefferanzahl. So lässt sich bereits im Vorfeld einschätzen, ob eine Suche nach dem entsprechenden Ausdruck sinnvoll ist.

In diesem Fall ist jeder Tastendruck, den Sie eingeben, während sich der Cursor im Suchfeld befindet, ein auslösendes Ereignis. Sparen Sie sich jedoch die Mühe, im Quelltext der Suchseite von Google Suggest etwas Verständliches zu finden. Das SELFHTML-Beispiel zum Event-Handler onkeydown verrät Ihnen das Prinzip, wie eine Ereignisbehandlung dieser Art in JavaScript mit einfachen Mitteln zu bewerkstelligen ist.

Der Unterschied etwa zum erwähnten SELFHTML-Beispiel besteht darin, dass das JavaScript, das bei Google Suggest auf Tastendruck hin gestartet wird, im Hintergrund eine HTTP-Anforderung an den heimischen Server sendet. Dort erzeugt ein serverseitiges Programm aus dem Datenbankbestand von Google die Daten der kleinen Dropdown-Liste und sendet sie an das aufrufende JavaScript. Aus den erhaltenen Daten wird dann über DOM-Methoden die Dropdown-Liste in den HTML-Code der angezeigten Google-Suggest-Webseite eingefügt.

Übrigens arbeiten fast alle neueren Google-Services intensiv mit Ajax. Das Bewegen etwa im bekannten Service Google Maps basiert ebenso auf Ajax-Kommunikation wie das automatische serverseitige Zwischenspeichern beim Verfassen von E-Mails in Google Mail.

Beispiel 2: TurboDBAdmin

Dieses Beispiel werden Sie am ehesten nachvollziehen können, wenn Sie schon einmal mit einer grafischen Verwaltungsoberfläche für Datenbank-Management-Systeme gearbeitet haben. TurboDBAdmin ist eine web-basierte Verwaltungsoberfläche für MySQL. Eine Live-Demo des Freeware-Produkts ist auf dem Server des Anbieters aufrufbar:

http://www.turboajax.com/turbodbadmin_demo/

TurboDBAdmin Links in der explorer-artigen Auswahl wird als oberster Eintrag der Host angezeigt, dessen Datenbanken verwaltbar sind. In der nächsten Ordnungsebene folgen die verwaltbaren Datenbanken. Im Demo ist dies lediglich eine einzige Datenbank. In der dritten Ordnungsebene werden die Tabellen der Datenbank angezeigt. Klicken Sie auf eine der Tabellen, z.B. PC-Res. Im Hauptbereich der Anwendung werden nun die Inhalte der Tabelle angezeigt. Die angezeigten Daten sind reichlich sinnlos, da es nur eine Testdatenbank ist, in der jeder — auch Sie — Datensätze einfügen, ändern oder löschen kann.

Wenn Sie beispielsweise auf eine der Spaltenüberschriften klicken, ändert sich die Sortierung der Tabelle so, dass nach der angeklickten Spalte sortiert wird. Dabei kommt Ajax zum Einsatz. Beim Anklicken (Event-Handler onclick) der Spaltenüberschrift wird ein JavaScript gestartet, das über HTTP ein serverseitig ausgeführtes Script aufruft. Dieses Script fragt mit einem SQL-Statement die Datenbank so ab, dass die neue Sortierung zustande kommt. Die erhaltenen Daten werden über HTTP an das aufrufende JavaScript übergeben. Das JavaScript sort für die Änderungen im HTML-Code der angezeigten Seite.

Mit der Menüschaltfläche Create Row können Sie der aktuell angezeigten Tabelle einen neuen Datensatz hinzufügen. Schreiben Sie einfach in die Tabellenzellen. Über die Menüschaltfläche Apply Edit können Sie die Eingaben speichern. Auch dabei wird wieder ein JavaScript aufgerufen, das via Ajax-Schnittstelle bzw. HTTP ein serverseitiges Script aufruft, das die Daten übergeben bekommt und in die Datenbank schreibt.

Dies ist nicht der Ort, um die einzelnen Möglichkeiten und Funktionen von TurboDBAdmin zu beschreiben. Wenn Sie selbst einen Webserver verwalten (beispielsweise auch einen lokal installierten Webserver) und PHP und MySQL in dessen Umgebung integriert haben, können Sie TurboDBAdmin downloaden und einfach in der eigenen Umgebung ausprobieren. TurboDBAdmin wird hier deshalb erwähnt, weil es eine typische ajax-basierte Webanwendung ist, von deren Sorte zur Zeit mehr und mehr entstehen.

Beispiel 3: web-basierter Chat von Fritz Weisshart

Ein idealtypisches Beispiel für den Einsatz für Ajax ist ein Chat. Denn ein Chat benötigt eine einen Server, damit die Chat-Teilnehmer interaktiv Text eintippen und die beigetragenen Inhalte anderer anwesender Teilnehmer sehen können. Das IRC-Protokoll, das für Internet-Chats gedacht ist, ist für Chat-Verbindungen optimiert. Dennoch haben viele Webanbieter auch den Wunsch, einen web-basierten Chat auf ihren Seiten anzubieten. Eine mögliche Lösung dafür stellt der Ajax-basierte Chat von Fritz Weisshart dar:

http://webdesign.weisshart.de/chat/

Weisshart-Chat Der Link führt direkt zu einer Live-Demo des Chats. Zum Testbesuch können Sie sich mit den Daten Gast und demo anmelden.

Die Anwendungsoberfläche, die dann erscheint, ist dem Fensterinhalt eines Chat-Clients nachempfunden. Im Hauptbereich stehen zuletzt gepostete Beiträge. Rechts werden anwesende Benutzer angezeigt, und der Wechsel zu weiteren Chat-Räumen ist möglich. In dem Eingabefeld unterhalb des Hauptbreichs können Sie selbst Text eintippen und sofort beitragen.

Damit der Eindruck einer Live-Teilnahme entsteht, muss in regelmäßigen, relativ kurzen Intervallen eine Kommunikation zwischen JavaScript und Server stattfinden. Im Weisshart-Chat ist sie per Default auf 1 Sekunde eingestellt, wobei die Intervalle jedoch dynamisch seltener werden, je inaktiver der Chat ist (dies verrät ein Blick in den Quelltext des Chat-JavaScripts). Solche Konzepte sind auch nötig, um den Webserver nicht zu überlasten. Über die JavaScript-Methoden setTimeout() und setInterval() ist es möglich, JavaScript-Code intervall-gesteuert automatisch auszuführen. Der so ausgeführte Code kann selbstverständlich auch eine HTTP-Kommunikation über die Ajax-Schnittstelle starten. Auf genau diesem Prinzip basiert der Chat. Serverseitig verwaltet ein PHP-Script die aktuellen Logins und die aktuell verfügbaren Beiträge. Neue Beiträge oder Änderungen bei den anwesenden Benutzern werden an das aufrufende JavaScript übergeben. Dessen Aufgabe besteht dann darin, hinzugefügte Beiträge einzufügen und gegebenenfalls die Liste der Benutzer zu aktualisieren.

In Verbindung mit einer Server-Push-Technologie wäre es sogar möglich, einen Ajax-Web-Chat nicht in Form von intervall-gesteuerten Ajax-Aufrufen zu gestalten, sondern ereignisabhängig. Dann würde das verarbeitende Chat-Script auf dem Server nur aufgerufen, wenn ein Teilnehmer etwas beiträgt oder z.B. ein neuer Teilnehmer den Raum betritt. Das Script könnte den Server dann veranlassen, den neuen Chat-Zustand an alle übrigen Teilnehmer zu senden, ohne von ihnen einen HTTP-Request erhalten zu haben (Server-Push). Da heutige Webserver jedoch aus teils guten Gründen keine Server-Pushs unterstützen, bleibt die intervall-gesteuerte Ajax-Kommunikation in einem Chat wie dem von Fritz Weisshart die einzige Wahl.


Dienstag, 3. April 2007

Tutorial: Ajax (1)

Ajax erfordert ein solides Vorwissen sowohl in JavaScript und dem Document Object Model (DOM), als auch in einer serverseitigen Web-Programmiersprache wie PHP, Perl oder Python. XML-, HTML- und CSS-Kenntnisse werden in vielen Fällen ebenfalls benötigt, sowie nicht selten auch Kenntnisse in Datenbank Management Systemen wie etwa MySQL. Und last but not least sind Kenntnisse über Einzelheiten des HTTP-Protokolls von Vorteil. Wirklich eine Menge Know-How also, weshalb die Ajax-Technologie auch eher im Profibereich angesiedelt ist.

Lassen Sie sich dennoch nicht gleich abschrecken. Wenn Sie von den zuvor genannten Sprachen und Technologien wenigstens schon einmal gehört und eine ungefähre Vorstellung davon haben, werden Sie zumindest die prinzipielle Funktionsweise von Ajax verstehen.

Was ist Ajax?

Für Ajax ist es wichtig zu verstehen, wie die HTTP-Kommunikation üblicherweise abläuft. Werfen wir deshalb zunächst einen kurzen Blick darauf, wie eine Webseite zum aufrufenden Browser kommt. Durch Anklicken eines Links, Eintippen einer Web-Adresse oder Auswählen eines Bookmarks sendet der Browser des Benutzers einen sogenannten HTTP-Request los. Das HTTP-Protokoll muss sich nicht darum kümmern, wie die Anfrage zum gemeinten Webserver gelangt. Dies übernimmt das TCP-Protokoll. Der Inhalt eines HTTP-Requests sieht ungefähr so aus:

GET /search/label/Ajax HTTP/1.1
Host: webkompetenz.blogspot.com
Connection: close
Accept-Encoding: gzip
Accept: text/xml,application/xml,application/xhtml+xml,text/html;
        q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.1) 
            Gecko/20061204 Firefox/2.0.0.1

Sie müssen nicht alles aus dem Beispiel verstehen. Es genügt zu wissen, dass GET ein HTTP-Kommando ist, mit dem der aufrufende Browser nach Daten verlangt. Die Domain, von der er diese Daten verlangt, ist im Beispiel webkompetenz.blogspot.com. Die Web-Pfadadresse, die er innerhalb dieser Domain verlangt, lautet im Beispiel /search/label/Ajax. Daraus ergibt sich folgende vollständige URL-Adresse:
http://webkompetenz.blogspot.com/search/label/Ajax
Das ist die Adresse, die der aufrufende Browser angefordert hat.

In den weiteren Informationen sendet der Browser noch diverse Informationen darüber mit, etwa in welcher Form er Daten akzeptiert, und wer er selber ist (seine eigene Produktidentifizierung).

Der aufgerufene Webserver beantwortet das GET-Kommando mit einem Response-Kommando. Das Response-Kommando besteht in jedem Fall aus einem HTTP-Statuscode sowie einem HTTP-Header, bestehend aus einem oder mehreren Header-Feldern. Was ein Web-Browser, der obige Webadresse angefordert hat, also beispielsweise als Antwort erhält, könnte in etwa so aussehen:

RESPONSE HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Last-Modified: Thu, 29 Mar 2007 13:27:46 GMT
Cache-Control: max-age=0 private
Etag: "98d95bd1-a138-4c47-a780-3a2bafe45368"
Content-Encoding: gzip
Date: Thu, 29 Mar 2007 19:48:28 GMT
Server: GFE/1.3

Auch das müssen Sie nicht alles verstehen. Die erste Zeile im Beispiel ist der HTTP-Statuscode. Die Nummer 200 bedeutet: alles in Ordnung, angeforderte Daten sind vorhanden, verfügbar und werden gesendet. Die übrigen Angaben sind HTTP-Header-Felder, beispielsweise zum Inhaltstyp der Daten oder zur Datenkompression.

Im Anschluss an dieses Set aus HTTP-Statuscode und HTTP-Header-Feldern folgen in unserem Fall die eigentlichen Nutzdaten, also der HTML-Code der angeforderten Webseite.

HTTP-Kommunikation „zwischendurch“

Kommunikation zwischen Browser und Webserver findet also dann statt, wenn der Browser eine neue URL-Adresse vom Webserver anfordert. Das kann die Primär-URL sein, die ein Anwender durch Anklicken eines Links, Eintippen einer URL-Adresse oder durch ein Bookmark aufruft. Es können aber auch sekundäre URLs sein, etwa URLs von Grafiken oder Flashmovies, die im HTML-Code der aufgerufenen Seite referenziert sind. Sind jedoch alle zu den eigentlich angeforderten Daten gehörenden Datenressourcen angefordert und übertragen, gibt es bis zur nächsten typischen Anwenderaktion (Link klicken, URL-Adresse eintippen, Bookmark aufrufen) keine weitere Kommunikation mehr zwischen Browser und Webserver – es sei denn, Ajax kommt ins Spiel!

Während eine vom Webserver übertragene Webseite im Browser angezeigt wird, kann sich im Browserfenster durchaus einiges tun. Die angezeigte Webseite enthält beispielsweise ein Navigationsmenü, das sich in verschiedene Zustände bringen lässt. Oder es sind Inhalte per Mausklick ein-/ausblendbar. Solche Effekte werden über Scripts gesteuert, die zu den Daten gehören, die mit der angeforderten Webadresse übertragen wurden. Das Script läuft vollständig im Browser ab. Der Browser verfügt über einen entsprechenden Script-Interpreter.

Die übliche Programmiersprache hierfür ist JavaScript. In Verbindung mit dem Document Object Model (DOM), das moderne Browser in ihre Script-Interpreter integriert haben, und mit der Technik der sogenannten Event-Handler ist es möglich, Inhalte einer gerade angezeigten Webseite abhängig von Benutzerereignissen zu manipulieren. So ist es beispielsweise möglich, dass eine Box beim Überfahren mit der Maus optisch hervorgehoben wird, oder dass ein Listenpunkt beim Anklicken um einen erläuternden Text erweitert wird. All das kann JavaScript, und all das passiert im Browser. Es besteht zu diesem Zeitpunkt keine Verbindung zwischen Browser und Webserver.

Mit Ajax erhält JavaScript jedoch eine weitere wichtige Arbeitsschnittstelle: es kann nun auch über HTTP mit einem Webserver kommunizieren, genauso, wie der Browser es selbst tut.

Dadurch wird es möglich, HTTP-Requests an Event-Handler zu binden und über HTTP erhaltene Daten über die DOM-Schnittstelle dynamisch in die bereits angezeigte Webseite zu integrieren!

Das klingt zunächst sehr abstrakt und nicht besonders sensationell. Betrachten wir jedoch ein einfaches praktisches Beispiel:

In einem HTML-Formular für Selbstregistrierungen kann sich ein Benutzer einen Benutzernamen nach Wunsch vergeben. Der Name muss jedoch eindeutig sein. Dazu könnte eine Schaltfläche „Prüfen“ angeboten werden. Wenn der Benutzer darauf klickt, ruft das durch den onclick-Event gestartete JavaScript via Ajax auf dem heimischen Web­server ein PHP-Script auf und übergibt ihm als Parameter den vom Anwender eingegebenen, gewünschten Benutzernamen. Das PHP-Script schaut in einer Datenbank auf dem Server nach, ob der Benutzername schon vorhanden ist. Wenn ja, sendet es FALSE zurück (Benutzername ist leider schon vergeben), wenn nein, TRUE (Benutzername ist noch nicht vergeben, also frei). Das aufrufende JavaScript bastelt aus dieser Information eine Ausgabe wie „Benutzername ist verfügbar“ oder „Benutzername ist leider nicht verfügbar“ und platziert diese über die DOM-Schnittstelle in der Umgebung des Eingabefeldes. Aus Sicht des Anwenders bleibt die aufgerufene Webseite am Bildschirm stehen. Das JavaScript tut scheinbar etwas Übliches: ausgelöst durch einen Event, blendet es via DOM-Schnittstelle eine Information ein. Ungewöhnlich ist jedoch, dass diese Information auf einer im Hintergrund abgelaufenen HTTP-Kommunikation zwischen JavaScript und einem Webserver basiert.

Wie dieses kleine Beispiel konkret realisierbar ist, werden wir im Praxisteil unserer Ajax-Einführung erfahren. An dieser Stelle ist zunächst wichtig zu verstehen, dass Ajax die HTTP-Kommunikationsschnittstelle in JavaScript ist, und dass sich dadurch zahllose neue Möglichkeiten eröffnen, um vor allem Webanwendungen für Benutzer attraktiver und schneller zu machen.


Sonntag, 25. März 2007

Neue Serien im Webkompetenz-Blog

Nachdem das Tutorial zu Mikroformaten nun fertig ist und auch in PDF-Form vorliegt, läuft derzeit nur noch die etwas kleinere „Serie“ über den Google Grid. Nachdem das nach und nach entstandene Tutorial über Mikroformate ganz gut angekommen ist, werde ich das Konzept der Fortsetzungsartikel weiter verfolgen. Wie aus Zeitschriften, Funk und Fernsehen bekannt, bindet das regelmäßige Besucher. Außerdem entspricht es den Richtlinien moderner Ernährung (immer nur kleine Häppchen), die sich sicherlich auf auf die geistige Ernährung übertragen lassen :-)

Bei den Tutorials steht als nächstes eine Einführung in Ajax an. Dieses Thema ist um einiges komplexer als das über Mikroformate. Über Ajax gibt es dicke Fachbücher. Ein Tutorial in diesem Rahmen kann kein solches Fachbuch ersetzen. Es möchte einfach nur all jenen, die mit HTML/CSS vertraut sind und mit JavaScript und PHP oder Ähnlichem schon mal herumgespielt haben, einen ballastfreien Einstieg in die Materie vermitteln.

Zeitgleich wird noch eine weitere Fortsetzungs-Artikelserie starten, nämlich eine Einführung in Hypertext. Wer SELFHTML kennt, weiß vermutlich, dass es dort bereits eine Einführung in Hypertext gibt. Die hier geplante Einführung wird ähnlich strukturiert sein, jedoch neue Texte enthalten und zusätzlich versuchen, die Hypertext-Thematik im Zusammenhang mit Web-2.0-typischen Web-Phänomenen zu beleuchten. Keine wissenschaftliche Abhandlung soll das werden, sondern eine nicht-technische Einführung für alle, die nicht nur bewusstlos auf Links herumklicken wollen.


Sonntag, 11. Februar 2007

Technik-Tutorials

Gedanken-Blogging ist eine feine Sache. Aber wenn man von den meisten Leuten nach wie vor mit einer Dokumentation wie SELFHTML identifiziert wird, darf ein wenig Technische Dokumentation natürlich nicht fehlen.

Deshalb habe ich mich entschlossen, dieses Blog demnächst (genauer will ich mich da nicht festlegen) auch mit Beiträgen zu bereichern, die kleine Einführungen in neuere, spezielle Web-Techniken darstellen. Den Anfang werden Mikroformate machen, und danach soll ein wenig Einsteigerwissen zu Ajax vermittelt werden. Die Einführungen werden sich nicht an das Hype-Publikum richten, das sich ohnehin dauernd auf den neuesten Techie-Seiten herumtreibt und schon alles kennt, sondern eher an jenes Publikum, das zwar schon Basiskenntnisse etwa in HTML oder JavaScript mitbringt, aber erst zögernd beginnt, sich mit den neueren Möglichkeiten auseinanderzusetzen.

Die Einführungen werden in Blog-gerechte Häppchen aufgeteilt, die über einen gewissen Zeitraum hinweg alle paar Tage in diesem Blog veröffentlicht werden. Sind alle Häppchen einer Einführung veröffentlicht worden, wird die gesamte Einführung als PDF-Dokument dauerhaft zur Verfügung gestellt. Die PDF-Dokumente werden im Webkompetenz-Forum als Dateien hochgeladen, aber auch hier im Blog in der Navigation fest verlinkt. Zu einem späteren Zeitpunkt können die Inhalte der Dokumente natürlich auch noch in andere Publikationsformen einfließen.

Also bitte nicht wundern, wenn hier demnächst nicht nur sinnierende, sondern zwischendurch auch deskriptive Texte mit Code-Beispielen Einzug halten!


 

Get Free Shots from Snap.com