AJAX hat es erstmals möglich gemacht Formular-Eingaben ohne Neuladen der Seite zu validieren. Hier werden die notwendigen Grundlagen vermittelt um AJAX Formulare zu bauen. Im letzten Schritt gibt es eine Fallback-Lösung für Besucher mit deaktiviertem JavaScript.
Formulare sind eine Möglichkeiten um Eingaben des Benutzers zu erhalten. Ein Formular muss mindestens die Attribute "action" und "method" haben.
Das "method"-Attribut gibt die HTTP Request Methode an, über die die Daten transferiert werden. Das kann entweder POST oder GET sein.
GET Daten werden über die URL übertragen - sie sind also für jeden Betrachter und auch in den Logfiles sichtbar. Für Formulareingaben sollte dies niemals verwendet werden.
Die Eingabe wird nicht direkt an das Formular - sondern mit einem HTTP Request an eine zweite URL - geschickt. Diese gibt man über das "action"-Attribut an.
Man kann die Eingabe auch an das Formular selbst schicken - das ist eine gute Praxis, wenn man nicht seinen Code nicht über zu viele Dateien verstreuen will.
|
HTML Code
|
1
2
3
|
<form action="" method="post">
...
</form>
|
Formulare haben verschiedene Feldtypen wie einzeilige und mehrzeilige Texteingaben, Auswahlboxen und -Listen mit einfach und mehrfach Auswahl und Feldtypen für Dateiuploads.
Die einfachste Platzierung ist schlicht, sehr gängig und enthält eigentlich alle notwendigen Informationen:
|
HTML Code
|
1
|
<input type="checkbox" name="checkbox1[]" value="1"/> Beschreibung der Auswahlbox Beschreibung
|
Schönere Formularfelder mit besserer Semantik erhält man, indem die Beschreibung mittels eines Labels dem Eingabefeld zugeordnet wird. Dazu muss dem Eingabefeld eine eindeutige ID vergeben werden:
|
HTML Code
|
1
2
3
4
|
<input type="checkbox" id="checkbox1" name="checkbox1[]" value="1"/>
<label for="checkbox1">
Beschreibung der Auswahlbox
</label>
|
Dies hat den praktischen Nebeneffekt, dass man nur den Text klicken braucht um die Auswahlbox zu de-/selektieren.
Eingabefelder lassen sich meist gruppieren. Um so mehr Eingabefelder es gibt, desto eher sollte sich der Entwickler darüber Gedanken machen.
Der Benutzer kann so eine bessere Übersicht gewinnen. Vor allem da HTML hier praktische Elemente liefert, die der Benutzer durch die Verbreitung auf vielen Websites schnell unterbewusst wahrnimmt. Es handelt sich dabei um s.g. "Fieldsets". Um diese "Fieldsets" zu beschriften fügt man eine Legende hinzu.
|
HTML Code
|
1
2
3
4
5
6
7
|
<fieldset>
<legend>Demo</legend>
<input type="checkbox" id="checkbox1" name="checkbox1[]" value="1"/>
<label for="checkbox1">
Beschreibung der Auswahlbox
</label>
</fieldset>
|
Selbstverständlich gehören alle Elemente die gleichzeitig übertragen werden müssen innerhalb eines einzige Formulars. Sie stehen im Zieldokument unter der Superglobalen $_POST zur Verfügung. Als Index wird der Formularname verwendet. Ein Besonderfall bilden mehrdeutige Elemente. So kann zum Beispiel der Typ Checkbox mehrere Werte annehmen.
Dazu muss man die Array-Schreibweise mit öffnender und schließender eckigen Klammer verwenden und erhält in PHP ein Array, über das man am besten mit einer foreach-Schleife iterierten kann.
|
PHP Quellcode
|
1
2
3
|
foreach($_POST['checkbox'] as $val) {
printf("%s wurde angeklickt<br/>", $val);
}
|
Dass $_POST ein normales Array ist erkennt man auch daran, dass sich die print_r Funktion darauf anwenden lässt.
Um Formulardaten über POST mittels AJAX zu übertragen muss ein GET String zusammengebaut werden, so wie man ihn hätte auch direkt im Browser aufrufen können.
Ein vollständiger POST Request sieht Ende wie folgt aus:
|
JavaScript Code
|
1
2
3
4
5
|
var postData = 'var1=value&var2[]=value&var2[]=value';
var req = window.XMLHttpRequest ? new XMLHttpRequest(): new ActiveXObject("Microsoft.XMLHTTP");
req.open('POST', 'destination.php', true);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send(postData);
|
Die selbstgeschriebene Funktion getFormData ist sehr trickreich. Man sagt dass sie das "Formular serialisiert". Der GET String wird zusammengebaut (Alternativ kann sie auch ein Array liefern). Sie iteriert über "form.elements" - also alle Elemente des Formulars. Auswahllisten haben den Sonderfall, dass alle Kindelemente (also die options) abgefragt werden müssen.
An dieser Stelle setze ich die Funktion einfach als gegeben voraus:
|
JavaScript Code
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
function getFormData(form, asArray) {
var ret;
var add = function(n, v) {
if(asArray) {
if(ret == null) ret = new Array();
ret[n] = escape(v);
} else {
ret = (ret == null ? '' : ret+'&') + n +'='+ escape(v);
}
};
for(var i=0; i<form.elements.length; i++) {
var el = form.elements[i];
var type = (el.type || '');
if(type.match(/^(text|hidden|textarea)$/i) || (type.match(/^(radio|checkbox)$/i) && el.checked)) {
add(el.name, el.value);
} else if(el.nodeName.match(/^select$/i)) {
for(var j=0; j<el.options.length; j++) {
if(el.options[j].selected) {
add(el.name, el.options[j].value);
}
}
} else if(el.nodeName.match(/^textarea$/i)) {
add(el.name, el.value);
}
}
return ret != null ? ret : (asArray ? new Array() : '');
}
|
Die bewährteste Möglichkeit um an Formulardaten zu gelangen, ist es sich in den onsubmit Event des Formular-Objektes einzuhängen.
Der onsubmit Event wird noch ausgeführt bevor das "action"-Attribut ausgelesen wird. Wird das Event mit false terminiert, dann fährt der Browser nicht fort und ignoriert es gar. Das ist die perfekte Voraussetzung für einen AJAX Request.
Als Nebeneffekt wird das onsubmit bei deaktiviertem JavaScript nicht gelesen und man landet direkt bei der Zielseite.
|
HTML Code
|
1
|
<form action="post.php" method="post" onsubmit="alert(getFormData(this));return false;">
|
Bei unserem Beispielformular mit nur einem Element sieht der Alert wie folgt aus:
Das Übertragen des gesamten Formulars per AJAX ist ein Zusammensetzen der bekannten Funktionen.
|
HTML Code
|
1
|
<form action="post.php" method="post" onsubmit="return ajaxPost(this.action, getFormData(this),'ajaxResponse');">
|
Der AJAX POST Request wurde in die Funktion ajaxPost übernommen. Diese sieht wie folgt aus:
|
JavaScript Code
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
function ajaxPost(url, postData, callback) {
var req;
try {
req = window.XMLHttpRequest ? new XMLHttpRequest(): new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
// browser does not have ajax support
}
req.onreadystatechange = typeof callback == 'function' ? callback : function() {
if (req.readyState == 4 && req.status == 200) {
if(typeof callback == 'string') callback = document.getElementById(callback);
if(callback) callback.innerHTML = req.responseText;
}
};
req.open('POST', url, true);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send(postData);
return false;
}
|
Zum Abschluss möchte ich eine Variante erläutern, wie man einfache Formulare parallel "mit" und "ohne" AJAX betreiben kann.
Ich habe mich dafür entschieden, dass das Formular die Daten an sich selbst schickt. Außerdem will ich unterscheiden ob die Daten per AJAX oder nicht per AJAX gesendet wurden. Daher füge ich allein im onsubmit Event die POST Variable "ajax" hinzu.
Der Formularkopf sieht nach der Bearbeitung wie folgt aus:
|
HTML Code
|
1
2
3
4
|
<form
action="<?php echo $_SERVER['REQUEST_URI']?>"
method="post"
onsubmit="return ajaxPost(this.action, 'ajax&'+getFormData(this),'ajaxResponse');">
|
Zusätzlich kümmert man sich im Kopf der Datei um die Bearbeitung des Requests. Falls es sich um einen AJAX Request handelt wird die Meldung direkt ausgegeben und ein exit ausgeführt. Das verhindert, dass der Rest der Seite neu geladen werden muss.
Ansonsten
|
PHP Quellcode
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<?php
$response = '';
if(count($_POST)) {
$response = sprintf('<b style="color:green">%s</b>', 'form data ok');
try {
// validation
if(!isset($_POST['radio1'])) throw new Exception('you have to add at least one option');
} catch(Exception $e) {
$response = sprintf('<b style="color:red">%s</b>', $e->getMessage());
}
if(isset($_POST['ajax'])) {
echo $response;
exit;
}
}
?>
|
Eine Live Demo mit allen möglichen Formularelementen findet ihr unter
http://demo.easy-coding.de/ajax/forms-with-and-without-ajax. Des weiteren wird der kompletten Code hier als ZIP Archiv zur Verfügung gestellt:
download.zip.