Suchfunktion mit Ajax
Schnellfinder

DeveloperIT-ProjekteSoftware

Web-Oberflächen mit Ajax liegen voll im Trend. Internet Professionell zeigt in dieser und den folgenden Ausgaben geniale Anwendungsbeispiele für diese neue Programmiertechnik. Den Anfang macht eine Live-Suche.

Ohne Reload

Suchfunktion mit Ajax

Kaum ein anderer Begriff prägt die Welt der Web-Entwicklung in den letzten Monaten so sehr wie Ajax (Asynchronous Javascript and XML). Seit Google einige Anwendungen wie Google Mail oder Google Maps mit dieser Technik umgesetzt hat, sind Ajax-basierte dynamische Lösungen gefragt. Durch den Einsatz asynchroner Datenübertragung kann eine Web-Anwendung in vielen Fällen der Bedienung von Desktop-Applikationen angeglichen werden. So auch in den Beispielen dieser Ausgabe. Anhand eines Adressbuchs wird gezeigt, wie ein Datenbestand on the fly, also noch während der Eingabe von Suchbegriffen, durchsucht werden kann und wie diese Suchergebnisse auch direkt im Browser verändert werden können. Der Clou an der Sache ist, dass dabei die Seite kein einziges Mal neu geladen werden muss und somit für den Benutzer keine lästigen Wartezeiten entstehen.

Die Verwendung einiger Bibliotheken macht die Entwicklung solcher Seiten zum Kinderspiel. Der Kern einer jeden Ajax-Anwendung sind Funktionen, die den asynchronen Datenaustausch zwischen Browser und Server abwickeln. Glücklicherweise existieren hierzu im Internet eine Vielzahl von Lösungen, die sich in der Regel weniger durch ihre Funktionen als in der Art der Schnittstelle und des Datenformats unterscheiden. Für die Beispiele dieses Artikels fiel die Wahl auf die Open Source Library Ajason (www.sourceforge.net/projects/ajason). Im Gegensatz zu der Mehrzahl an Ajax-Bibliotheken arbeitet Ajason nicht mit XML als Datenaustauschformat, sondern basiert auf Json, das deutlich weniger große Datenpakete erzeugt. Somit geht der Datenaustausch zwischen Browser und Server schneller vonstatten. Zudem ist Ajason komplett objektorientiert, sowohl auf Javascript- als auch auf PHP-Seite.


Suchfunktion

Suchfunktion mit Ajax

Bietet eine Webseite oder Web-Anwendung die Möglichkeit, nach Daten zu suchen, ist der Ablauf meist folgender: Der Benutzer gibt einen Suchbegriff ein und klickt einen Button. Daraufhin wird eine Seite mit den Suchergebnissen geladen. War die Suche zu ungenau, verändert der Benutzer die Suchbegriffe und klickt erneut auf den Suchen-Button, was eine veränderte Ergebnisseite zur Folge hat. Dieses Spiel wiederholt sich so lange, bis ein befriedigendes Ergebnis vorliegt.

Mit Ajax-Programmiertechnik ist es möglich, dieses Verfahren deutlich zu vereinfachen und somit auch Wartezeiten für den suchenden User zu verringern. Bei einer Live-Suche werden bereits bei der Eingabe die Suchdaten asynchron an den Server übertragen, der die Werte aus einer Datenbank ausliest, filtert und das Ergebnis an den Browser zurückliefert. Der Benutzer sieht sofort, wie sich Änderungen an den Suchbegriffen auswirken.


Live-Search mit Ajax

Suchfunktion mit Ajax

So viel zur Theorie. Wie lässt sich nun eine solche Funktion in die Realität umsetzen? Ganz einfach: Bei jeder Eingabe in das Suchfeld wird im Hintergrund per Ajax eine Anfrage an ein PHP-Skript auf dem Server gestellt. Dieses liest die existierenden Adressen aus einer Datenbank und filtert sie anhand der bisher eingegebenen Suchbegriffe. Das folgende Listing zeigt einen Ausschnitt aus dem PHP-Skript zur Filterung der Adressen mit regulären Ausdrücken:


$sqlite =& new SPSQLite("address.sqlite");
$sqlite->query("SELECT * FROM address");
$rs = $sqlite->returnRows();
foreach($rs as $row)
{
$nMatches = 0;
foreach ($arrSearchKeys as $strRegEx)
{
if (preg_match("/^".$strRegEx."/i", $row["strFirstName"]) )
{
$nMatches++;
continue;
}
if (preg_match("/^".$strRegEx."/i", $row["strLastName"]) )
{
$nMatches++;
continue;
}

Die so gewonnenen Treffer werden als Array von Objekten an die aufrufende HTML-Datei zurückgeliefert, wo sie per Javascript in HTML-Quellcode umgewandelt und im Browser ausgegeben werden. Dieser Schritt wiederholt sich bei jeder Eingabe in die Suchbox. Somit wird das Suchergebnis laufend, also live, an die Eingabe angepasst.


Entlastung für den Server

Suchfunktion mit Ajax

Wenn Ihnen beim Lesen nun der Gedanke gekommen ist, dass eine Serveranfrage nach jedem Tastendruck eine große Belastung des Webservers darstellt, dann liegen Sie richtig. Durch einen kleinen Trick wird der Server von unnötigen Anfragen entlastet:


var objTimer = null;
function liveSearchStart()
{
if (objTimer) {
window.clearTimeout(objTimer);
}
objTimer = window.setTimeout("doLiveSearch()", 500);
}

Die Funktion liveSearchStart wird bei jedem Tastendruck in der Suchbox aufgerufen. Damit dies bei der Eingabe längerer Suchbegriffe nicht jedes Mal zu einer Suchanfrage an den Server führt, wird die Suchanfrage über einen Timer aufgerufen, der erst eine halbe Sekunde nach dem Tastendruck auslöst. Findet in der Zwischenzeit ein weiterer Tastendruck statt, so wird der Timer zurückgesetzt. Auf diese Weise startet die Suchanfrage nur, wenn länger als eine halbe Sekunde keine Eingabe mehr erfolgt. Da die meisten Benutzer schneller tippen, wird die Suchanfrage erst nach Vollendung eines Suchworts ausgeführt.


Hilfe

Suchfunktion mit Ajax

Damit der Benutzer die Wirkung seiner Eingaben besser beurteilen kann, werden die Teile der Adresse farblich hervorgehoben, die mit den Suchwörtern übereinstimmen. Auch können durch die Verwendung von regulären Ausdrücken zur Suche auf dem Server mehrere Teilbegriffe in das Suchfeld eingegeben werden. So findet die Suchanfrage »Herr Muster 74« alle männlichen Einträge, in deren Adresse Muster vorkommt und deren Postleitzahl mit 74 beginnt.

Durch die asynchrone Verarbeitung der Eingaben mit Ajax müssen zur Einschränkung des Suchergebnisses nicht immer die Seiten neu geladen werden. So läuft eine Suche in der Regel schneller ab als in einer klassischen Web-Anwendung.


Ergebnisse

Suchfunktion mit Ajax

Der aufwendigste Teil der Echtzeitsuche ist die Umsetzung der reinen Suchergebnisdaten in HTML-Quellcode. Einer der Kritikpunkte an Ajax ist das Problem, wie der HTML-Code erzeugt wird, der nach Server-Anfragen für den Browser aufbereitet werden muss.

Zwei Möglichkeiten stehen hierfür zur Verfügung, die jedoch ihre Vor- und Nachteile besitzen. Eine Lösung ist das Erzeugen des HTML-Quellcodes durch die per Ajax aufgerufene PHP-Server-Klasse und das anschließende Anzeigen im Browser per Javascript. Diese Vorgehensweise hat den Nachteil, dass die PHP-Server-Klasse nur mit einer bestimmten Webseite benutzt werden kann, da speziell für diese Seite die Ausgabe erzeugt wird. Für objektorientierte Anwendungen, die oftmals Template-Systeme zur Anzeige verwenden, ist dies eine schlechte Lösung.

Bei der zweiten Möglichkeit liefert die Server-Klasse nur die Daten als Array oder Objekte. Auf der Javascript-Seite werden diese per Javascript-DOM-Befehle in HTML-Objekte wie Tabellen und Zellen umgesetzt und eingefügt. Dies ist eine mühselige und fehleranfällige Vorgehensweise, hat aber den Vorteil, dass die PHP-Server-Klasse verschiedene Webseiten bedienen kann.


Template-Engine

Suchfunktion mit Ajax

Javascript-Templates sind hier die Lösung der Wahl. Aufbauend auf dem zweiten Lösungsansatz werden die gelieferten Daten anhand eines Templates von einer Bibliothek in gültigen HTML-Quellcode umgesetzt. Im Beispiel dieses Artikels wird die Open-Source-Template-Engine JST (www.trimpath.com/project/wiki/JavaScriptTemplates) dazu verwendet, um die rohen Daten des PHP-Server-Skripts in HTML umzuwandeln. Dabei spielen drei Komponenten eine Rolle.

Zum einen sind die Daten selbst wichtig, die als eine Anzahl von Arrays oder Objekte wie im folgenden Beispiel vorliegen und im Fall des Adressbuches von PHP erzeugt werden.


var data = {
values : { salutation: 'Herr',
lastname: 'Mustermann',
firstname: 'Manfred',
street: 'Musterweg 1',
postalcode: '77777',
city: 'Musterhausen',
id: 1 }
};

Um die Daten in HTML umzusetzen, benötigt JST zudem eine Vorlage, die als unsichtbares TextArea-Element am Ende des HTML Quellcodes eingebunden wird. Dieses Template enthält Platzhalter, die mit Daten der Arrays und Objekten gefüllt werden.




Schleifen und mehr

Suchfunktion mit Ajax

JST leistet aber noch viel mehr, als hier gezeigt werden kann. So können beispielsweise Schleifen und Verzweigungen in die Templates eingebaut werden. Darüber hinaus lassen sich auch beliebige Javascript-Befehle während der Template-Verarbeitung ausführen. Das Template result_jst für die Ausgabe der Suchergebnisse macht hiervon ausgiebig Gebrauch, um beispielsweise Treffer farblich zu markieren.

Die dritte notwendige Komponente ist die eigentliche Template-Engine. Sie führt die Daten mit dem Template zusammen und liefert einen String mit HTML-Quellcode, der in ein HTML-Objekt wie einem DIV eingefügt werden kann.


objDiv=document.getElementById("mydiv);
output=TrimPath.processDOMTemplate("ok_jst", data);
objDiv.innerHTML=output;


Direct Editing

Suchfunktion mit Ajax

Wie zu Beginn des Artikels erwähnt, soll mit der Beispielanwendung nicht nur nach Daten gesucht werden, sondern diese sollen auch gleich geändert werden können. Natürlich ist dies auch mit PHP-Skripts möglich. Eine Ajax-Lösung bietet aber hier etliche Vorteile. Während normalerweise zum Bearbeiten immer ein Seitenwechsel mit einer neuen Maske notwendig wird, können die Änderungen beim Direct Editing direkt in der Ergebnistabelle vorgenommen werden. Auch das gleichzeitige Bearbeiten von mehreren Einträgen ist dann kein Problem, was praktisch sein kann, um Daten eines Eintrags in einen anderen zu kopieren.

Zur Realisierung dieser Funktionen ist ebenfalls nur eine geringe Menge an Javascript-Code in Verbindung mit den bereits besprochenen Bibliotheken Ajason und JST notwendig. Beim Klick auf den Ändern-Link einer Zeile wird folgende Funktion mit der eindeutigen ID einer Zeile aufgerufen:


function editAddress(nId)
{
objRow = document.getElementById("tr_"+nId);
arrPrevValues[nId] = objRow.innerHTML;
var data = {
values : { salutation: getTagValueByPosition(objRow, "TD", 0),
lastname: getTagValueByPosition(objRow, "TD", 2),
firstname: getTagValueByPosition(objRow, "TD", 1),
street: getTagValueByPosition(objRow, "TD", 3),
postalcode: getTagValueByPosition(objRow, "TD", 4),
city: getTagValueByPosition(objRow, "TD", 5),
id: nId }
};
var output = TrimPath.processDOMTemplate("edit_jst", data);
replaceRowContent(objRow, output);
}


Suchfunktion mit Ajax

Um die Tabellenzeile zu bearbeiten, werden hier zuerst die Werte der einzelnen Tabellenspalten in ein Array gefüllt. Mit diesen Werten wird anhand eines JST-Templates der HTML-Code einer Tabellenzeile generiert, die statt der Textwerte Auswahl- und Eingabefelder besitzt. Der bisherige HTML-Quellcode wird gesichert, damit bei einem Abbruch der Bearbeitung der Originalzustand wieder hergestellt werden kann. Anschließend wird der neue HTML-Quellcode eingefügt. An dieser Stelle gilt es eine weitere Browserfalle zu umgehen. Der Internet Explorer weigert sich, Änderungen an Tabellen und Tabellenzeilen über das innerHTML-Attribut vorzunehmen. Daher muss der Umweg über die Hilfsfunktion replaceRowContent gemacht werden, um die Werte einer Zeile auszutauschen. Für die Aktionen Ok und Abbrechen wird der umgekehrte Weg eingeschlagen. Wenn die Änderungen mit Ok bestätigt werden, wird anschließend noch ein Schreiben der Daten auf dem Server per Ajax angestoßen.


Schwierigkeiten

Suchfunktion mit Ajax

Einen genaueren Blick ist die Funktion getValueByTagPosition wert. Um an die Zellenwerte einer Zeile zu gelangen, ist es am einfachsten, die td-Objekte anhand ihrer Position anzusprechen. Um auf die dritte Zelle der Spalte zuzugreifen, wäre folgender Code die nahe liegende Lösung:

value = objRow.childNodes[2];

Auf den ersten Blick sollte die Lösung funktionieren ? hat doch ein tr-Element nur td-Unterelemente. Weit gefehlt! Jeder Zeilenumbruch und jedes Leerzeichen führen dazu, dass die Browser ein Unterelement vom Typ Text einfügen und der einfache Zugriff über das Attribut childNodes nicht mehr funktioniert. Die Funktion getValueByTagPosition liefert dagegen zuverlässig den Wert einer bestimmten Spalte in einer Zeile:


function getTagValueByPosition(objElement, strTagName, nPosition)
{
nCurPosition = 0;
for (nIndex = 0; nIndex < objElement.childNodes.length; nIndex++) {
if (objElement.childNodes[nIndex].nodeName == strTagName)
{
if (nCurPosition == nPosition)
{
return objElement.childNodes[nIndex].innerHTML;
}
nCurPosition++;
} } }

Die gezeigte Direct-Editing-Lösung weist noch Verbesserungspotenzial auf. So wäre es denkbar, dass die Eingaben vom PHP-Server-Skript noch validiert werden. Enthalten Felder ungültige Eingaben, so wird das Ok-Kommando nicht weiter ausgeführt, und der Benutzer könnte sofort mit einer Fehlermeldung darauf aufmerksam gemacht werden. Auch dies kann alles per Ajax im Hintergrund geschehen.


Fazit

Suchfunktion mit Ajax

Mit einigen Bibliotheken für Ajax und HTML-Verarbeitung ist es ein Leichtes, Web-Oberflächen zu entwickeln, die deutlich schneller arbeiten und intuitiver für den Benutzer zu bedienen sind als herkömmliche Internetseiten. Wer sich näher mit den besprochenen Themen befassen möchte, kann sich anhand der Quelltexte des Adressbuch-Beispiels einen besseren Überblick verschaffen. Die vorhandenen Skripts können als Ausgangspunkt für die Verwendung in eigenen Anwendungen dienen. Allerdings sollte vor dem Einsatz immer gut abgewogen werden, ob Live-Search und Direct-Editing wirklich zur Verbesserung der Bedienoberfläche beitragen oder nur als Effekthascherei dienen.


Alle Listings zum Workshop finden Sie auf der Heft-CD und unter listings.internet-pro.de.