Functies buiten de belangrijkste gebruikersroute vergeten we vaak, of we kiezen voor een heel eenvoudige implementatie. Zulke subtiele interacties en uitzonderingssituaties maken een product merkbaar prettiger, maar kosten vaak te veel tijd om te bouwen. Toch weten we allemaal dat details ertoe doen.
Hiervoor moeten we binnen een Phoenix LiveView-project een formulier en de bijbehorende changeset opzetten en de gegevens valideren. We zijn ook dol op Tailwind, dus ik heb een voorbeeldproject voorbereid waarin alles samenkomt. Geen zorgen: we nemen het ook stap voor stap door.
We beginnen met de HTML-template (heex):
We gebruiken de standaardfunctiecomponent voor formulieren van Phoenix en plaatsen die in een fraai vormgegeven div. Het formulier bevat twee eigen functiecomponenten: <.input /> en <.button />. Ieder invoerelement krijgt een eigen container voor foutmeldingen, die we dus in de definitie moeten vastleggen.
De code hierboven rendert simpelweg een fraai invoerelement dat aan de functiecomponent van het formulier wordt gekoppeld. Als je met de CLI een Phoenix-project maakt, wordt een module met de naam ErrorHelpers gegenereerd. Die gebruik je vervolgens in een formulier met <%= error_tag @f, @name %>. Je vindt dit bestand in lib/errortags_web/views/error_helpers.ex. We maken er een functiecomponent voor onze LiveView-opzet van (regel 6):
~use Phoenix.HTML~
use Phoenix.LiveComponentDaarna passen we de definitie van error_tag aan om onze fraaie foutmelding te tonen, inclusief animatie:
Nu kunnen we de foutcomponent boven onze <%= text_input ... %> plaatsen. Deze is alleen zichtbaar als je changeset een fout bevat.
<.error_tag f={@f} name={@name} />
Dit is het resultaat tot nu toe:
but we’re missing the red border around the input element!
Om vast te stellen of het formulier een fout bevat, moet onze input-functiecomponent weten dat er een fout is. Die logica staat alleen in de functiecomponent error_tag, niet in de input-functiecomponent. We willen voorkomen dat we op meerdere plekken dezelfde code schrijven om fouten uit het formulier op te halen, zeker als we dit systeem ook op andere input-functiecomponenten willen toepassen, bijvoorbeeld een checkbox-component.
Gelukkig bieden Phoenix slots uitkomst. Daarvoor moeten we wel een deel van onze code herschrijven.
We voegen een slot has_error? toe aan onze input-functiecomponent en plaatsen die in de functiecomponent error_tag, zodat we gegevens kunnen doorgeven. Zoals je hierboven ziet, wordt deze om de component heen geplaatst en gebruikt als form_tag. De HTML voor de fout blijft hetzelfde, maar eindigt met <%= render_slot(...) %>. Daar wordt de input-functiecomponent gerenderd, met als tweede parameter een boolean. Zo blijft error_tag verantwoordelijk voor het vaststellen van een fout, terwijl onze input-functiecomponent daarop wordt aangepast:
Hier plaatsen we het invoerelement in de slot. Ook hebben we de class van text_input aangepast, zodat er bij een fout een duidelijke rand omheen verschijnt.
Dit kan ook op andere manieren, maar we houden de implementatie voor het renderen van een invoerveld graag zo eenvoudig mogelijk. Dat is gelukt: gebruik onderstaande code en je krijgt de fraaie foutmelding er automatisch bij.
<.input f={f} name={:email} />
Wil je het zelf proberen? Je vindt de voorbeeldcode op 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>