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"
    style="display: none"
    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.


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.