Formular per AJAX verschicken

Wenn ein HTML-Formular abgeschickt wird, lädt normalerweise die Seite neu. Das ist vielleicht nicht immer die beste User-Experience, im Sinne von Progressive Enhancement aber der beste Ausgangspunkt.

Wenn wir für Benutzer*innen, die JavaScript aktiv haben (und bei denen das Laden und Verarbeiten der JS-Ressourcen geklappt hat) die Erfahrung verbessern wollen, bietet es sich in manchen Fällen an, das Formular per AJAX zu verschicken, sodass die Seite nicht neugeladen werden muss.

Update vom 2. September: Lars hat mich auf die Existenz von fetch() aufmerksam gemacht, eine modernere Alternative zu XMLHttpRequest für Requests. Ich habe den Artikel entsprechend angepasst.

Der erste Impuls könnte sein, beim submit-Event des Formulars oder beim click-Event des Submit-Buttons per document.querySelector(".input-selector").value die Werte der einzelnen Formularfelder zu ermitteln und dann damit irgendwie einen AJAX-Request zusammenzubauen.

Es geht aber deutlich einfacher, und zwar mit der FormData-Klasse. Damit sieht das Versenden eines Formulars per AJAX beispielhaft wie folgt aus:

(function() { // IE does not support fetch(). if (!window.fetch) { return; } const form = document.querySelector("form"); if (!form) { return; } form.addEventListener("submit", async function(e) { e.preventDefault(); const form = e.target, data = new FormData(form), method = form.method.toUpperCase(), url = form.action; const response = await fetch(url, { method, body: data, headers: { "X-Requested-With": "XMLHttpRequest" } }); if (response.ok === false) { // Something wrong with the request. return; } // Do something with the result (in response.json() for JSON responses). }); })();
Code-Sprache: JavaScript (javascript)

Zunächst prüfen wir, ob der Browser fetch() unterstützt (der Browser-Support für fetch() ist gut) und speichern das erste form-Element auf der Seite in der form-Konstante. Nach einer Prüfung, ob überhaupt ein Formular vorhanden ist, hängen wir eine asynchrone Funktion an das submit-Event des Formulars an (asynchron deswegen, um innerhalb der Funktion await nutzen zu können).

In dieser Funktion verhindern wir mit e.preventDefault() das normale Absenden des Formulars und das Neuladen der Seite und erstellen anschließend ein paar Konstanten:

  • form bekommt das abgesendete Formular zugewiesen. An sich könnte hier auch form von außerhalb der Funktion weitergenutzt werden, so funktioniert der Code aber auch, wenn der Event-Listener direkt an das Ergebnis von querySelector() angehängt werden sollte.
  • data beinhaltet die Rückgabe des FormData-Konstruktors, an den das gesamte Formular-Element übergeben wird. Das praktische: das können wir gleich als Daten für den Request nutzen, und haben damit alle Felder des Formulars im Request, die normalerweise auch verschickt werden würden.
  • method speichert die Methode des Formulars und
  • url speichert die URL, an die die Daten geschickt werden sollen.

In Zeile 19 bis 25 schicken wir den Request an die URL aus dem action-Attribut des Formulars ab und übergeben als zweiten Parameter ein Objekt mit zusätzlichen Daten für den Request, nämlich:

  • die Art des Requests method (da der Wert dafür in der gleichnamigen Konstante method gespeichert ist, genügt es, method zu übergeben statt method: method),
  • in body die Daten des Formulars,
  • (optional) den X-Requested-With-Header, damit etwa Laravels $request->ajax()-Methode erkennt, dass es sich um einen AJAX-Request handelt. Hier nutzen wir als Wert XMLHttpRequest, etwas wie fetch hat bei mir nicht funktioniert.

Durch Nutzung von await wird der Code danach erst ausgeführt, wenn wir eine Antwort auf den Request haben. Dann prüfen wir über response.ok ob der Status-Code der Antwort im 200er-Bereich liegt und können Dinge mit den Daten anstellen, die wir zurückbekommen haben.

Und das war’s auch schon, wir verschicken damit das Formular ohne Neuladen der Seite via AJAX.

10 Reaktionen zu »Formular per AJAX verschicken«

  1. Hi! Alles schön schlank und größtenteils für Anfänger wie mich verständlich, großen Dank! Aber noch eine Frage: wie binde ich ein bestimmtes von mehreren Formularen auf einer Seite ein? Der querySelector 'form' greift sich ja wohl immer das erste...mit getElByID klappt es auch nicht...hast du Rat? Und noch ne Kleinigkeit: "form gleich e.target" ... wofür steht 'target'? Danke!
    Joachim

    1. Hi,

      du kannst den Wert in querySelector auf jeden beliebigen CSS-Selektor anpassen. Wenn dein form-Element beispielsweise die Klasse special-form hat, könntest du querySelector( '.special-form' ); schreiben.

      Das target ist das Element, für den der Event-Listener gefeuert wurde, also im Beispiel das Formular.

      Viele Grüße

Reposts

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert