leestijd
5 min

Bewerkbare content in Phoenix LiveView

Het probleem

We vinden dat een formulier, of iets wat daarop lijkt, niet altijd in een interface past. Soms moet een bewerkbare waarde er juist uitzien als de gewone interface die je al hebt. Dat levert wel een enigszins verborgen UI op en daar kun je anders over denken, maar wij kozen voor de implementatie uit de video bovenaan en zijn er blij mee.

We hebben het zo gebouwd omdat op iedere pagina een titel staat die aangeeft waar je je in het beheerpaneel van mave bevindt. De titel helpt je navigeren en begrijpen waar je bent. Op de pagina van een geüploade video wordt standaard de bestandsnaam als titel gebruikt. We kregen veel verzoeken om die titel te kunnen wijzigen. Daarom kun je erop klikken; de titel verandert dan in iets wat op een invoerveld lijkt: het contenteditable-element.

Helaas bevat Phoenix LiveView op dit moment geen kant-en-klare component om contenteditable-elementen binnen een <.form /> te beheren. Voor gewone invoervelden heb je bijvoorbeeld text_input/3, dat normaal gesproken een invoerelement met de bijbehorende gegevens rendert.

De oplossing

Laten we bekijken hoe je iets vergelijkbaars bouwt. We beginnen met onze component, die uit een beetje HTML bestaat. Vervolgens voegen we CSS-classes toe — wij gebruiken Tailwind — zodat de component er tijdens het bewerken uitziet zoals je van een gewoon invoerveld verwacht:

Nu moeten we zorgen dat de component goed met Phoenix samenwerkt. Daar zijn meerdere manieren voor. Je kunt bijvoorbeeld met een JavaScript-MutationObserver wijzigingen in het contenteditable-element volgen en die via een phx-hook koppelen. Wil je later echter ook foutafhandeling toevoegen zoals we eerder deden, met de standaardmogelijkheden van de Phoenix-component <.form />, dan moet je daarvoor een omweg bouwen. Daarom gebruiken we de formuliercomponent met hidden_input/3. Zo kun je gewoon je Ecto.Changeset gebruiken en de invoer op de gebruikelijke manier valideren. Ook voegen we het attribuut contenteditable toe:

We hebben enkele assigns aan de component toegevoegd, zodat we hem opnieuw kunnen gebruiken. Nu willen we wijzigingen in het contenteditable-element doorgeven aan hidden_input en omgekeerd. Daarvoor kunnen we opnieuw de MutationObserver gebruiken, maar we kunnen ook afzonderlijke gebeurtenissen volgen, zoals keyup. Voordat we onze hook opzetten, voegen we een id en phx-hook="content_editable" toe. Daarnaast passen we een handig trucje toe: als de titel te lang wordt, korten we hem af. In onze HTML laten we Phoenix de tekenreeks inkorten. We willen een lange titel echter wel volledig kunnen opslaan en bewerken, dus zonder ... aan het einde te bewaren. Daarom voegen we een data-attribuut toe dat we in onze hook gebruiken:

Laten we nu onze hook content_editable maken. Geen zorgen als je hem nog niet meteen begrijpt:

Het is een flinke hoeveelheid code, dus ik loop hem met je door. Alles begint in de functie mounted(), waar de gebeurtenissen worden ingesteld. Wanneer je op het element klikt en het daardoor focus krijgt, tonen we de volledige titel die Phoenix via het attribuut data-title doorgeeft. Is de titel ingekort, dan verschijnt in het element dus alsnog de volledige tekst.

Zodra focusout plaatsvindt of je op Enter drukt, wordt save() aangeroepen. Die functie doet precies wat de naam belooft. De toetsenbordgebeurtenis wordt geactiveerd door keyup en roept showText() aan. Die verwijdert ook de overbodige nieuwe regels die door de Enter-toets ontstaan. focusout vindt plaats wanneer je buiten een element klikt dat focus had, of wanneer we blur() op het element aanroepen — dat doen we zodra je op Enter drukt.

Bij het opslaan korten we de tekst opnieuw in en wijzigen we de waarde van het formulierelement alleen als die daadwerkelijk anders is. Om ervoor te zorgen dat Phoenix het formulier afhandelt, moeten we een gebeurtenis op het invoerelement activeren.

Dat is alles. We hebben nu een contenteditable-component in Phoenix:

Je kunt de definitieve code op GitHub bekijken.

Gepubliceerd op 27 oktober 2022
werkt met
Ontwikkelaar?
Onze documentatie begeleidt je bij het embedden van video: van eenvoudige eerste stappen tot handmatige configuraties voor ervaren gebruikers. Je vindt er meerdere hostingopties, waaronder ons standaard-CDN, en uitleg over populaire webframeworks.
script
react
vue
1
2
3
4
5
🍪 Klik op ‘Accepteren’ om te bevestigen dat je het ermee eens bent dat we geen cookies gebruiken. Ja, deze banner is puur voor de show!
Accepteren