Ajax-Programmierung - Teil 2

15.10.2006 von Elmar Fuchs
Die Webprogrammierung mit Ajax beschränkt sich nicht auf den Einsatz in herkömmlichen HTML-Enwicklungsumgebungen. Auf Lotus Notes Domino basierende Webseiten können ebenfalls von Ajax profitieren.

In der letzten Ausgabe von Expert's inside Lotus Notes/Domino haben wir uns mit den Grundlagen von Ajax (Asynchron JavaScript and XML) beschäftigt. Nach der Betrachtung der theoretischen Aspekte wurde an einem kleinen Beispiel die praktische Vorgehensweise beim Einsatz von Ajax gezeigt. Als zentrales Element von Ajax wurde dabei das Objekt XMLHttpRequest hervorgehoben. Dessen Eigenschaften und Methoden sowie deren Anwendung bei der Nutzung des Objekts standen im Mittelpunkt der Ausführungen.

Nachdem wir jetzt wissen, wie wir Ajax in einer Webseite nutzen können, wollen wir in diesem Artikel das Beispiel in die Notes Domino- Welt übertragen. Dabei wird die Gestaltung der Webseite mit Hilfe einer Notes-Maske erfolgen. Darüber hinaus nutzen wir auch einen typisches Notes-Gestaltungselement zur Beantwortung der Anfrage des XMLHttpObjekts: einen Agenten. Und obwohl dessen Einsatz über den Browser erfolgt, verwenden wir zu dessen Programmierung LotusScript.

Voraussetzung ist eine Notes-Datenbank

In unserem Beispiel wird nach der Auswahl eines Buches der zugehörige Autor mittels Ajax auf die Webseite eingefügt. Für die Realisierung in unserer „Notes-freien“ Umgebung hatten wir im letzten Artikel auf ein sehr einfaches PHP-Skript zurückgegriffen, welches in Abhängigkeit vom übergebenen Wert den jeweiligen Autorenname lieferte.

Da wir jetzt Lotus Notes Domino als Umgebung verwenden, legen wir natürlich auch die Daten über die Bücher in der Notes-Datenbank ab. Zu diesem Zweck erstellen wir auf dem Domino Server eine neue Notes-Datenbank und fügen in diese eine Maske Buch (Alias ebenfalls Buch) mit mindestens drei Feldern (Titel, Buchkuerzel und Autor) vom Text ein. Alle drei Felder sind bearbeitbar. Weitere Feldeigenschaften müssen nicht gesetzt werden. Um ein Mindestmaß an Benutzerfreundlichkeit einzuhalten, setzen wir vor die Felder statische Texte zur Beschreibung der Feldinhalte und fügen Schaltfläche zum Bearbeiten, Speichern und Schließen hinzu. Erfassen Sie im Anschluss einige Beispieldokumente (Bild 1).

Bild 1: Beispieldokumente für die Anwendung.
Bild 2: Schlatflächen für die wichtigsten Dokumente.

Für die Suche nach einem Dokument mit LotusScript stehen Ihnen verschiedene Möglichkeiten offen. Neben der freien Suche und der Suche auf Basis eines Volltextindex können Sie auch Dokumente innerhalb einer Ansicht suchen. Da wir diese Vorgehensweise verwenden wollen, benötigen wir eine Ansicht. Sie bekommt den Namen Bücher (Alias Buecher) und zeigt die Buchkürzel und die Namen der Autoren an. Die erste Spalte ist aufsteigend sortiert. Auch hier können Sie zumindest einige Schaltflächen für die wichtigsten Arbeitsschritte einfügen (Bild 2).

Webseite erstellen

Für die Webseite verwenden wir eine Maske Buchwahl (Alias Buchwahl). Deren Aufbau entspricht dem der im letzten Artikel genutzten Webseite. Nach einer kurzen Überschrift fügen Sie zur Auswahl der Buchtitel ein Feld Titel vom Typ Kombinationsfeld ein. Auf dem Register Steuerung der Infobox des Feldes wählen Sie im Bereich Auswahl den Eintrag Auswahl eingeben (eine pro Zeile). Im darunter liegenden Listenfeld können Sie die Titel der Bücher und als Alias für jeden Eintrag das zugehörige Buchkürzel erfassen.

Bild 3: Die Maske zur Auswahl von Büchern.

In einer echten Anwendung würde man natürlich auf die in der Ansicht erfassten Buchtitel zurückgreifen und diese mit den entsprechenden Aliaseinträgen kombinieren. Für unsere Zwecke soll aber die geschildert Vorgehensweise ausreichen. Legen Sie nun noch auf dem Register <HTML> die ID des Feldes fest. Tragen sie dazu im Feld ID den Eintrag Titel ein. Dies gewährleistet, dass bei Zugriff mit der JavaScript- Funktion getElementById diese in allen Browsern den korrekten Wert liefert.

Unterhalb des Feldes benötigen wir noch einen Container, in den der Autorname nach der erfolgreichen Durchführung der Serveranfrage eingefügt wird. Erstellen Sie den Container mit dem Tag

<div id="autorName"></div>

Markieren Sie zum Schluss alle Maskenelemente, und weisen Sie ihnen die Eigenschaft Durchgangs- HTML zu. Wählen Sie dazu den Menüpunkt Text/Durchgangs-HTML.

Ajax-Funktionen einbauen

Der benötigte JavaScript-Programmcode unterscheidet sich nur unwesentlich von dem beim Einsatz in einer reinen HTML-Seite.

Im Ereignis JS-Header (Listing 1) wird das Objekt XMLHttpRequest erstellt. Die Vorgehensweise entspricht der im vorigen Artikel erläuterten. Über drei Try-Catch-Blöcke wird getestet, welcher Browser der Anwender nutzt, und das entsprechende Objekt deklariert.

var xmlhttp = false;
try {
xmlhttp = new XMLHttpRequest();
} catch(mi) {
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (miv2) {
try {
xmlhttp = new ActiveXObject ("Microsoft.XMLHTTP");
} catch (fehler) {
alert ("XMLHttpObjekt konnte nicht erstellt werden!");
}
}
}
function seiteAktualisieren() {
if (xmlhttp.readyState == 4)
if (xmlhttp.status == 200) {
var autor = xmlhttp.responseText;
document.getElementById("autorName").innerHTML = autor;
} else
alert("Es ist ein Fehler aufgetreten. Fehlernummer: " + xmlhttp.status);
}

Die Funktion seiteAktualisieren ist Ihnen, wenn Sie den vorigen Artikel gelesen haben, ebenfalls bekannt. Die Funktion wird in Abhängigkeit von den Werten des Objektstatus sowie des zurückgegebenen Serverstatus ausgeführt. Sie liest das Ergebnis der Anfrage aus und schreibt es in den vorbereiteten Container der Webseite.

Die Instanzierung des Objekts XMLHttpRequest und die Ausführung der Anfrage erfolgt im Ereignis onChange des Kombinationsfeldes Titel. Hier unterscheidet sich der Aufruf der vom Server auszuführenden Anfrage, da wir ja kein PHPSkript, sondern einen LotusScript-Agenten verwenden wollen.

Der Einsatz von LotusScript ist im Zusammenhang mit dem Web im Regelfall mit den Maskenereignissen WebQueryOpen und Web- QuerySave verbunden. Diese werden ausgeführt, wenn eine auf einer Maske basierende Webseite geöffnet oder geschlossen wird. Dies entspricht jedoch nicht dem Grundprinzip von Ajax. Hier sollen die Daten nachgeladen werden, wenn eine Seite offen ist. Als Ausweg nutzen wir den Aufruf des Agenten über den URL-Befehl

<NameDesAgenten>?OpenAgent

Den benötigten Parameter hängen wir mit einer Zeichenkettenverknüpfung an den URL an, sodass sich insgesamt der Aufruf

"http://<Server>/<NameDB>.nsf/<NameDesAgent>?OpenAgent&<ParamName>="+<ParamWert>

ergibt. Dieser wird für den Parameter URL der Methode open() des Objekts XMLHttpRequest verwendet.

Weitere Änderungen in der Funktion seiteAktualisieren gegenüber dem bereits bekannten Beispiel fallen nicht an (Listing 2).

var buch = document.getElementById("Titel").value;
var url = "http://<Server>/ajaxdemo1.nsf/(AutorSuchen)?OpenAgent&buch="+buch;
xmlhttp.open("GET", url, true);
xmlhttp.onreadystatechange = seiteAktualisieren;
xmlhttp.send(null);

Rückgabewerte ermitteln

An Stelle des PHP-Skripts zur Ermittlung des Rückgabewerts wollen wir in unserer Lotus Notes/ Domino-Umgebung einen LotusScript- Agenten verwenden. Wie dieser aufzurufen ist, haben wir gerade gesehen. Bleibt die Frage, wie der Agent auf den im URL enthaltenen Parameter zugreifen kann.

Im Notes-Client ist es nicht möglich, einem Agenten beim Start einen oder mehrere Parameter zu übergeben. In unserem Fall erfolgt der Aufruf jedoch über das Web. Und hier ist es möglich, auf den URL, welcher zum Start des Agenten aufgerufenwurde, zuzugreifen. Beim Start des Agenten wird von der Session ein virtuelles Dokument für den Agenten erzeugt. Auf dieses können Sie über die Eigenschaft DocumentContext des ObjektsNotesSession zugreifen.

Dim agentDoc As NotesDocument
Set agentDoc = se.DocumentContext

Dieses Dokument enthält sowohl die Werte aller CGI-Variablen als auch den Inhalt des Query_String in gleichnamigen virtuellen Feldern. Beim Wert Query_String handelt es sich um den Teil des URL hinter dem Fragezeichen, also

OpenAgent&<ParamName>="+<ParamWert>

Diesen Wert können wir auslesen und einer Variablenzuweisen:

Dim queryString As String
queryString =
agentDoc.GetItemValue("Query_String")(0)

Da wir in unserem Beispiel nur einen Parameter verwenden, ist das dadurch notwendige Parsen des Ausdrucks recht einfach. Wir müssen nur den Textteil ermitteln, der hinter dem Gleichheitszeichen steht. Dazu deklarieren wir eine weitere Variable und speichern darin das Ergebnis der Trennzeichens in mehrere Bereiche

Dim queryStringParam
queryStringParam = Split(queryString, "=")

und speichert sie in einem Feld von Typ String. Das erste Element im Feld enthält danach den Text vor, das zweite Element den Text nach dem Gleichheitszeichen. Dieser ist der übergebene Parameterwert, den wir einer dritten Variablen zuweisen. Da Felder in LotusScript mit dem Wert 0 beginnen, greifen wir auf das Element <Feldname>( 1) zu:

Dim suchString As String
suchString = queryStringParam(1)

Bei der Verwendung mehrerer Parameter ist deren Ermittlung aus dem Query_String etwas aufwendiger, unter zu Hilfenahme der LotusScript- Funktionen zur Zeichenkettenbearbeitung aber möglich.

Der restliche Programmcode des Agenten (Listing 3) entspricht der üblichen Vorgehensweise, um ein Dokument in einer Ansicht zu finden. Über die Session wird auf die aktuelle Datenbank zugegriffen [1]. Diese ermöglicht den Zugriff auf eine Ansicht [2]. Die Ansicht wird Dokument für Dokument durchlaufen [3]. Dabei wird jedes Dokument auf das Vorhandensein des Suchstrings in dem Feld Buchkuerzel untersucht [4]. Entspricht der im Feld gespeicherte Wert dem Suchstring, wird mit der Anweisung Print der Name und die Abarbeitung des Agenten beendet [5]. Wurde nach dem Durchlaufen aller Dokumente kein passendes Buch gefunden, wird eine entsprechende Meldung als Rückgabewert der Anfrage geliefert [6].

Sub Initialize
Dim se As New NotesSession
Dim db As NotesDatabase
Dim vw As NotesView
Dim doc As NotesDocument
Dim agentDoc As NotesDocument
Dim queryString As String
Dim queryStringParam
Dim suchString As String
Dim gefunden As Boolean
gefunden = False
Set agentDoc = se.DocumentContext
queryString = agentDoc.GetItemValue("Query_String")(0)
queryStringParam = Split(queryString, "=")
suchString = queryStringParam(1)
Set db = se.CurrentDatabase [1]
Set vw = db.GetView("Buecher") [2]
Set doc = vw.GetFirstDocument [3]
While Not doc Is Nothing
If suchString = doc.GetItemValue("Buchkuerzel")(0) Then [4]
Print doc.GetItemValue("Autor")(0) [5]
gefunden = True
Exit Sub
End If
Set doc = vw.GetNextDocument(doc) [3]
Wend
If Not gefunden Then [6]
Print "Kein passendes Buch gefunden"
End If
End Sub

Bei einem Test der Funktion im Browser ist kein optischer Unterschied im Vergleich zur Umsetzung mit der HTML-Seite und dem PHPSkript festzustellen (Bild 4). Lediglich die minimal größere Antwortzeit lässt ahnen, dass im Hintergrund nicht ein schneller Apache-Server steht, sondern ein Domino-Server arbeitet.

Bild 4: Die fertige Ajax-Anwendung im Browser.

Wie geht es weiter?

Bis hierher haben wir uns eigentlich Aja und nicht Ajax angeschaut – XML ist noch nicht vorgekommen. Im nächsten Artikel wird sich das ändern. Nachdem wir wissen, wie wir die zugrunde liegenden Techniken sowohl in einer reinen HTML-Seite als auch in einer Notes/Domino- Umgebung nutzen, schauen wir uns an, wie und wo wir XML einsetzen können. Im Anschluss daran beschäftigen wir uns mit der Manipulation der Webseite unter Verwendung des Dokument Objekt Model (DOM) unter Berücksichtigung der Ergebnisse der Ajax-Anfrage.