3D-Grafik von Steve Johnson – https://unsplash.com/@steve_j

Interaktive Formulare mit Alpine.js

In diesem Beitrag dynamisiere ich ein Kontaktformular mit Alpine.js, um das Nutzererlebnis inkrementell zu bereichern.

Jairus Joer

Jairus Joer

Ausgangspunkt: Das Formular

Ein schlichtes Kontaktformular dient als Ausgangspunkt für die angestrebte Dynamisierung. Im nächsten Schritt wird das notwendige HTML und JavaScript definiert.

<form class="form">
  <input class="form-input" name="name" type="text" />
  <input class="form-input" name="email" type="email" />
  <textarea class="form-input" name="message"></textarea>
  <button type="submit">Absenden</button>
</form>

Alpine.js in das Formular integrieren

Die Installation und Einrichtung von Alpine.js ist für diesen Abschnitt vorausgesetzt. Mehr dazu in unserem Beitrag: Alpine.js in einer Produktions-Umgebung einbinden

Innerhalb des Alpine-Skripts registriert man den Kontext useForm und definiert die asynchrone post-Funktion wie folgt. Man beachte auch die Auslagerung der Datenformatierung auf die eigene Funktion data, welche eine flexiblere Einbindung der Daten innerhalb des Kontexts erlaubt.

Die data-Funktion gibt ein Objekt der hinterlegten Eingabewerte wieder, während die post-Funktion Daten als JSON als POST zu unserem (noch) fiktiven Backend sendet.

document.addEventListener("alpine:init", () => {
  Alpine.data("useForm", () => ({
    data() {
      const inputs = Array.from(this.$el.querySelectorAll("input, textarea"));
      const data = inputs.reduce((object, key) => ({ ...object, [key.name]: key.value }), {});
      return data;
    },

    async post() {
      return await (
        await fetch("/", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify(this.data()),
        })
      ).json();
    },
  }));
});

Im <form>-Element registrieren wir den zuvor definierten Kontext useForm, zusammen mit der post-Funktion, um die Datenerfassung mit Alpine abzuwickeln. x-on:submit.prevent ist Alpines Pendant zu Event.preventDefault(), unterbricht das Absenden des Formulars und löst stattdessen die post-Funktion aus.

<form class="form" x-data="useForm" x-on:submit.prevent="post">
  <input class="form-input" name="name" type="text" />
  <input class="form-input" name="email" type="email" />
  <textarea class="form-input" name="message"></textarea>
  <button type="submit">Absenden</button>
</form>

Antworten dynamisch anzeigen lassen

Dank Alpines Reaktivität können Antworten auf abgesendete Formulare genutzt werden, um Nutzer:innen ein sofortiges Feedback auf Ihre Anfragen zu liefern. Im folgenden Beispiel dient ein simples PHP-Skript als Backend, welches die Formular-Daten als JSON über die Variable $json zur Verfügung stellt und über $response ebenfalls ein JSON-Objekt zurückgibt.

Über $response->state wird der Status der Abfrage definiert, welcher unabhängig der Daten zurückgegeben wird. Die enthaltenen Informationen dienen zur Identifizierung, Darstellung und Kommunikation der Antwort im Frontend.

header("Content-type: application/json; charset=utf-8");

$json = json_decode(file_get_contents('php://input'));

$response->data= [
  // ...
];

$response->state = [
  'code'=> 200,
  'type' => 'success',
  'message'=> 'Ihre Anfrage wurde erfolgreich verschickt.'
];

http_response_code($response->state['code']);
exit(json_encode($response));

Im Alpine-Objekt response wird die Antwort der POST-Anfrage gespeichert und über den Kontext useForm für das HTML-Frontend zugänglich gemacht.

document.addEventListener("alpine:init", () => {
  Alpine.data("useForm", () => ({
    response: false,

    data() {
      const inputs = Array.from(this.$el.querySelectorAll("input, textarea"));
      const data = inputs.reduce((object, key) => ({ ...object, [key.name]: key.value }), {});
      return data;
    },

    async post() {
      this.response = await (
        await fetch("/", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify(this.data()),
        })
      ).json();
    },
  }));
});

Über x-show wird das Element .form-response durch die Antwort des Backends eingeblendet – hier in Form eines simplen Banners. Der zurückgegebene Statustyp success wird als neue Klasse .is-success registriert, um die Färbung des Banners zu beeinflussen.

<form class="form" x-data="useForm" x-on:submit.prevent="post">
  <div
    class="form-response"
    x-cloak
    x-show="response"
    x-bind:class="`is-${response?.state?.type}`"
    x-text="response?.state?.message"
    x-transition
  ></div>
  <input class="form-input" name="name" type="text" />
  <input class="form-input" name="email" type="email" />
  <textarea class="form-input" name="message"></textarea>
  <button type="submit">Absenden</button>
</form>

Somit können Antworten aus dem Backend über Alpine dynamisch dargestellt werden. In einem weiteren Schritt ließe sich diese Funktionalität auch zur Darstellung von Informationen zur Validierung einzelner Eingabefelder nutzen.

Aufgrund der großen Nachfrage haben wir einen Folgeartikel zur Arbeit mit erweiterten Formularen in Alpine.js erstellt. Lies unseren Artikel über Fortgeschrittene Formulare mit Alpine.js.


TL;DR

Mit Alpine wird ein statisches Formular um reaktive Features erweitert, welche das Senden, Empfangen und Visualisieren von Informationen aus dem Backend für Eingaben – mithilfe des Kontexts von Alpine – vereinfachen.