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

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.


Montag, 2. April 2007

Programmierer auf der Suche nach Code

Wer selber programmiert, gerät häufig in Situationen, in denen ein konkretes Code-Beispiel nützlich wäre. Das kann beim Lösen eigener Aufgabenstellungen helfen, oder es kann zumindest etwas Licht ins Dunkel einer Funktion, einer Methode, eines Operators oder Statements bringen.

Für Programmierer auf der Suche nach Code-Beispielen bietet Google im Rahmen seiner Umorientierung auf ein semantisches Netz eine spezielle Code-Suche an. Die entsprechende Suchseite ist unter www.google.com/codesearch zu finden.

Die Code-Suche arbeitet per Default mit regulären Ausdrücken. Nun ist deren Syntax nicht jedermanns Sache, doch nur so wird wirklich präzises Suchen möglich. Allerdings sind auch literale Zeichenketten als Suchausdruck erlaubt. Dazu kommen Syntax-Möglichkeiten, um die Suche auf bestimmte Programmiersprachen oder Dateitypen zu beschränken. Die Suchmöglichkeiten sind auf der Suchstartseite erläutert.

Nehmen wir ein Beispiel. Wer schon mal mit der Funktion pack zu tun gehabt hat, weiß, dass deren Syntax und Möglichkeiten sich nicht gleich jedem erschließen. In Sprachen wie Perl ist diese Funktion jedoch beispielsweise bestens geeignet, um eine UU-Enkodierung auf eine Zeichenkette anzuwenden. In das Suchfeld von Google's CodeSearch geben wir ein:

lang:"perl" \spack\("u"

Präsentiert wird uns dieses Ergebnis. Zu jedem gefundenen Perlscript, in dem pack("u" vorkommt, werden entsprechende Code-Ausschnitte in der Ergebnisanzeige der Suchtreffer gleich angezeigt. Die gefundenen Perlscripts sind anklickbar und führen zu vollständigen Listings der jeweiligen Scripts. Darin sind die gefundenen Suchtreffer nochmals optisch hervorgehoben.

Ein zweites Beispiel: wer hier fleißig mitliest, kennt das Tutorial zu Mikroformaten. Nun mag ein solches Tutorial beim Einstieg in die Materie helfen, doch es kann sicher nicht alle Frage beantworten. Angenommen, wir möchten ein paar konkrete Beispiele zu class="dtstart" (betrifft das hCalendar-Mikfoformat) sehen. Wir geben in der CodeSearch ein:

\sclass="dtstart"

In diesem Fall haben wir auf die Angabe der Sprache verzichtet, weil sich herausgestellt hat, dass auf diese Weise mehr Ergebnisse zustande kommen. Der Grund ist, dass HTML eben auch innerhalb von Programmiersprachen wie PHP häufig als Output vorkommt.

Das Beispiel zeigt aber auch, dass die Code-Bibliothek, die Google bislang zusammengetragen hat, noch nicht so umfangreich ist, wie das wohl später einmal sein soll. Kein Wunder, denn die Code-Suche befindet sich wie viele der anderen Google-Services noch im Beta-Stadium.

Und wie sucht sich die Code-Suche ihre Listings zusammen? Zum einen durch gewöhnliches Crawling, also durch das, was der Google-Robot tut, wenn er Webseiten besucht. Weitere Listings finden ihren Eingang in das Archiv der Code-Suche durch explizites Hinzufügen. Google bietet dazu ein Formular zum Beitragen von Code an.

Die Google Code Search hat aber, als sie im Oktober 2006 online ging, auch Bedenken ausgelöst. Vor allem wenn es dem Google-Robot gelingt, an den Quelltext etwa von PHP-Scripts zu kommen, die innerhalb der Document Root eines Webservers liegen, könnten ungewollt sensible Daten in das öffentlich durchsuchbare Archiv gelangen, beispielsweise Datenbankzugangsdaten, die im Script kodiert sind. Passieren kann ein solches Versehen, wenn aus irgendwelchen Gründen Backups von Webanwendungen in Form von GZIP- oder TAR-Archiven innerhalb der Document Root abgelegt sind, oder wenn — möglicherweise nur vorübergehend — einmal die Webserverkonfiguration fehlerhaft ist und aufgerufene Scripts nicht ausgeführt, sondern im Quelltext an den aufrufenden Client ausgeliefert werden.

Wenn Sie selber glauben, über lehrreiche Listings zu verfügen, die Sie gerne mit anderen teilen möchten, dann ist die Form des Veröffentlichens über das erwähnte Formular sicher eine geeignete Form.

Lesenswert zu diesem Thema:

Und last but not least natürlich die Google Code-Suche nach Bill Gates...


Freitag, 9. März 2007

Angenehme Popups mit Prototype-Window

Viele erinnern sich noch an die Zeiten, als das Aufrufen einer Webseite fast immer noch weitere kleine Fensterchen öffnete, mehr oder weniger viele, mehr oder weniger groß, und mit mehr, aber meistens weniger sinnreichem Inhalt. Schuld an den nervigen Fenstern war JavaScript (beim MS Internet Explorer: JScript).

Viele Web-Entwickler haben sich irgendwann von JavaScript abgewendet, nicht nur wegen der nervigen Popup-Fenster, die man damit erzeugen konnte, sondern auch deshalb, weil sie den ganzen JavaScript-Krempel der Vergangenheit leid sind, mit all den Browserweichen, Dokumentobjektmodellen, Sprachversionen usw. Mittlerweile erlebt die Scriptsprache jedoch einen neuen Boom, wobei Insider aber gar nicht mehr von JavaScript oder gar DHTML (lezteres ist ein absolutes Igitt-Wort geworden!) sprechen, sondern von DOM-Scripting. Der Grund ist, dass mittlerweile nur noch mit einem Dokumentobjektmodell gearbeitet wird, nämlich mit dem DOM des W3-Konsortiums. Darauf aufbauend sind in den letzten Jahren diverse frei verfügbare Code-Bibliotheken entstanden, mit deren Hilfe sich beeindruckende Funktionen erzielen lassen. Um einen kleinen Eindruck von dieser neuen Welt zu bekommen, soll hier mal eine Site vorgestellt werden, die das alles mustergültig vormacht: prototype-window.xilinus.com.

Rufen Sie dort zunächst mal die Themes-Seite auf, und klicken Sie die Links View a window und open a alert box an. Alle so erzeugten Layer (diese Bezeichnung ist wohl korrekter als Fenster, auch wenn es optisch eher wie Popup-Fenster aussieht) lassen sich frei verschieben, in der Größe verändern, maximieren, minimieren und schließen, können verschiedene skins (Layouts) haben, und der Inhalt kann aus allem bestehen, was auf einer Webseite möglich ist. Sinnvoll eingesetzt, ermöglichen solche Fenster durchaus einen Mehrwert für den Anwender zu schaffen dadurch, dass dieser nicht wegen jeder Zusatzinformation wieder eine neue Seite aufrufen muss.

Vielleicht sind Ihnen ähnliche Overlay-Fenster-Effekte in letzter Zeit auch schon öfters untergekommen. Auch die SnapIt-Popups bei Links wie diesem basieren auf Scripts dieser Art. Das Besondere an prototype-window.xilinus.com ist jedoch, dass alle Scripts und verwendeten Bibliotheken dort mustergültig dokumentiert werden. Für alle, die irgendwann zu JavaScript-Verweigerern wurden, könnte diese Site vielleicht eine neue Neugier wecken und demonstrieren, dass DOM-Scripting eigentlich nichts mehr für Script-Kiddies ist, sondern eher für „erwachsene“ Programmierer.


 

Get Free Shots from Snap.com