Oft vergessen wir, Dinge zu erstellen, die kein primärer Benutzerfluss sind, oder wir erstellen einfach eine einfache Implementierung dieser Dinge. Der Aufbau dieser subtilen Interaktionen und die Abdeckung bestimmter Randfälle sind Details, die sich bei der Implementierung wirklich gut anfühlen, deren Erstellung aber oft zu viel Zeit in Anspruch nimmt. Und wir alle wissen, dass es auf Details ankommt.
Damit dies funktioniert, müssen wir ein Formular und seinen Änderungssatz einrichten und die Daten innerhalb eines Phoenix LiveView-Projekts validieren. Wir lieben auch Tailwind sehr, deshalb habe ich ein Beispielprojekt für Sie vorbereitet, das alles enthält. Aber keine Sorge, wir gehen es auch Schritt für Schritt durch.
Lassen Sie uns zunächst die HTML-Vorlage (heex) einrichten:
Wir verwenden die Standard-Formularfunktionskomponente von Phoenix und haben sie in ein gut aussehendes Div verpackt. Innerhalb des Formulars gibt es zwei benutzerdefinierte Funktionskomponenten: <.input /> und <.button />. Jedes Eingabeelement erhält seinen eigenen Fehlermeldungscontainer, daher müssen wir diesen in seiner Definition deklarieren.
Das Obige rendert einfach ein gut aussehendes Eingabeelement, das mit der Formularfunktionskomponente verbunden wird. Wenn Sie mit der CLI ein Phoenix-Projekt erstellen, wird ein Modul namens ErrorHelpers generiert. Diese können Sie dann in einem Formular mit <%= error_tag @f, @name %> verwenden. Diese Datei finden Sie unter lib/errortags_web/views/error_helpers.ex. Ändern wir dies in eine Funktionskomponente für unser LiveView-Setup (Zeile 6):
~use Phoenix.HTML~
use Phoenix.LiveComponentUnd ändern Sie die Definition von error_tag, um unsere fantastisch aussehende Fehlermeldung mit Animation und allem anzuzeigen:
Jetzt können wir die Fehlerkomponente über unserem <%= text_input ... %> hinzufügen. Dies ist nur sichtbar, wenn Ihr Änderungssatz einen Fehler enthält.
<.error_tag f={@f} name={@name} />
Das soll das aktuelle Ergebnis unserer Bemühungen sein:
but we’re missing the red border around the input element!
Um herauszufinden, ob das Formular einen Fehler aufweist, müssen wir einen Weg finden, unserer Eingabefunktionskomponente mitzuteilen, dass ein Fehler vorliegt. Diese Logik befindet sich jedoch in der Funktionskomponente „error_tag“ und nicht in der Funktionskomponente „input“. Und wir sollten vermeiden, denselben Code zu schreiben, um an mehreren Stellen Fehler aus dem Formular zu erhalten, insbesondere wenn wir dieses Fehlersystem auf andere Eingabefunktionskomponenten anwenden möchten (z. B. in einer Kontrollkästchenkomponente).
Glücklicherweise sind Phoenix slots hier, um den Tag zu retten. Aber wir müssen einen Teil unseres Codes, den wir zuvor geschrieben haben, neu schreiben.
Wir fügen unserer Eingabefunktionskomponente einen has_error?-Slot hinzu und schließen ihn in diese error_tag-Funktionskomponente ein, damit wir einige Daten weitergeben können. Wie Sie oben sehen können, wird es verpackt und als form_tag verwendet. Der Fehler-HTML ist immer noch derselbe, endet aber mit <%= render_slot(...) %>. Hier wird die Eingabefunktionskomponente gerendert und enthält einen zweiten Parameter, der ein boolescher Wert ist. Auf diese Weise bleibt das error_tag dafür verantwortlich, uns darüber zu informieren, ob ein tatsächlicher Fehler vorliegt, aber unsere Eingabefunktionskomponente wird entsprechend aktualisiert, etwa so:
Hier stecken wir das Eingabeelement in den Steckplatz. Und wir haben auch die Klasse von text_input aktualisiert, um bei jedem Fehler einen schönen Rahmen um sie herum anzuzeigen.
Es gibt auch andere Möglichkeiten, dies zu erreichen, aber wir möchten die Implementierung, die zum Rendern einer Eingabe verwendet wird, so einfach wie möglich halten. Und das ist es, was wir haben. Verwenden Sie einfach das Folgende und wir erhalten eine nette Fehlermeldung:
<.input f={f} name={:email} />
Wenn Sie es ausprobieren möchten, finden Sie den Beispielcode auf Github.
1
2
3
4
5
<script type="module">
import { Player } from "https://cdn.video-dns.com/npm/@maveio/components/+esm";
</script>
<mave-player embed="ubg50Cq5Ilpnar1"></mave-player>
<script type="module">
import { Player } from "https://cdn.video-dns.com/npm/@maveio/components/dist/react.js";
</script>
<Player embed="ubg50Cq5Ilpnar1"></Player>
<script type="module">
import { Player } from "https://cdn.video-dns.com/npm/@maveio/components/+esm";
</script>
<mave-player embed="ubg50Cq5Ilpnar1"></mave-player>