## De kern van [[HTMX]]: Triggers en Geavanceerde Besturingstechnieken {#sec-f4f92dc347e1} In eerdere artikelen hebben we de basisprincipes van het versturen van verzoeken naar de server met [[HTMX]] besproken. Met attributen zoals `hx-get`, `hx-post`, `hx-put` en `hx-delete` hebben we gezien dat je nu veel Ajax-functionaliteit kunt implementeren zonder de `fetch()`-methode van JavaScript. Maar wanneer je [[HTMX]] gebruikt, wil je vaak meer controle over **wanneer een verzoek wordt verzonden**, in plaats van alleen hoe het wordt verzonden. Hier komt `hx-trigger` om de hoek kijken. Als `hx-get` of `hx-post` attributen zijn die bepalen **"wat" er moet gebeuren**, dan bepaalt `hx-trigger` **"wanneer" het moet gebeuren**. Zonder `hx-trigger` zou [[HTMX]] slechts een eenvoudige Ajax-tool lijken die alleen verzoeken verzendt wanneer op een knop wordt geklikt. Maar vanaf het moment dat je `hx-trigger` in [[HTMX]] gaat gebruiken, zal je tevredenheid toenemen. Dankzij `hx-trigger` zijn bijvoorbeeld de volgende dingen mogelijk zonder JavaScript-code: - Zoekverzoeken alleen verzenden nadat de invoer is gestopt - Dubbele klikken binnen een korte tijd voorkomen - Automatisch vernieuwen met een vast interval - Elementen alleen laden wanneer ze op het scherm verschijnen - Verzoeken alleen verzenden onder specifieke voorwaarden - Prioriteiten aanpassen om conflicten tussen verschillende verzoeken te voorkomen In het begin dacht ik ook: "Waarom [[HTMX]] gebruiken als een paar regels `fetch`-code volstaan?" Mijn houding, waarbij ik [[HTMX]] slechts als een eenvoudige Ajax-tool zag, veranderde volledig nadat ik de krachtige besturingsmogelijkheden van `hx-trigger` had ervaren. In dit artikel zullen we de **triggers en geavanceerde besturingstechnieken** van [[HTMX]] behandelen, die als de ware kern van de bibliotheek kunnen worden beschouwd.  --- ## [[HTMX]] is meer dan alleen een knoptool {#sec-31cdd005939f} Wanneer je [[HTMX]] voor het eerst tegenkomt, begin je meestal met een voorbeeld zoals dit: ```html
``` Op basis hiervan lijkt [[HTMX]] misschien gewoon een "tool die Ajax-verzoeken verzendt wanneer je op een knop klikt". Natuurlijk is dat op zich al handig. Maar dat is slechts een deel van [[HTMX]]. Het echte punt is dat je **het moment en de voorwaarden voor het verzenden van een verzoek direct in HTML kunt declareren**. Denk bijvoorbeeld aan: - Het verzenden van een verzoek naar de server bij elke typslag in een zoekbalk resulteert in een slechte gebruikerservaring. Het zou veel natuurlijker zijn als het verzoek pas 500ms nadat de invoer is gestopt, wordt verzonden. - Je wilt misschien dat een knop alleen werkt wanneer deze wordt geklikt **terwijl de Ctrl-toets is ingedrukt**. - Of je wilt gegevens alleen ophalen wanneer een specifiek element zichtbaar wordt na het scrollen. Als je voor elk van deze momenten JavaScript-code zou moeten schrijven, zou de code snel toenemen. [[HTMX]] daarentegen, kan dergelijke controles grotendeels **uitdrukken met een combinatie van attributen, zonder één regel JavaScript**. Dit is echt verbazingwekkend. De schok die ik voelde toen ik `hx-trigger` van [[HTMX]] voor het eerst zag, was misschien vergelijkbaar met de schok die een **C++-ontwikkelaar ervaart bij het zien van Python-code en denkt: 'Wat? Geen typeaanduidingen??'** --- ## Basistriggers: click, change, submit {#sec-a730147be101} Allereerst is het belangrijk te weten dat [[HTMX]] al is ontworpen om goed samen te werken met de standaardgedragingen van HTML-elementen. Een knop is bijvoorbeeld standaard gekoppeld aan `click`, een formulier aan `submit`, en invoerelementen aan `change`, afhankelijk van de situatie. ```html ``` Deze knop verzendt een verzoek bij een klik, zelfs zonder expliciet `hx-trigger="click"` te specificeren. Hetzelfde geldt voor formulieren. ```html ``` In dit geval wordt het verzoek verzonden bij het indienen van het formulier. Dit betekent dat [[HTMX]] in zeer basale scenario's al vrij intelligent werkt. Maar het deel waar we ons op moeten concentreren, begint hier. **Het zelf declareren van het gewenste moment en de gewenste voorwaarden, voorbij de standaardwaarden.** Dat is precies wat we willen doen. --- ## Veelgebruikte standaardgebeurtenissen versus [[HTMX]]-specifieke triggers in `hx-trigger` {#sec-8354ed76dc75} Allereerst is het essentieel om de onderstaande tabel te begrijpen. De kern is dat **standaard DOM-gebeurtenissen die de browser van nature biedt, uiteraard bruikbaar zijn, plus er zijn enkele [[HTMX]]-specifieke triggers.** | Categorie | Waarde | Betekenis | Veelvoorkomende scenario's | Voorbeeld | | ---------- | ----------------- | ---------------------------- | ----------------------------------- | ---------------------------------------------------------------------- | | Standaard gebeurtenis | `click` | Verzoek bij klik | Knoppen, links, actie-uitvoering | `hx-trigger="click"` | | Standaard gebeurtenis | `input` | Verzoek bij elke wijziging van invoerwaarde | Realtime zoeken, auto-aanvullen | `hx-trigger="input changed delay:500ms"` | | Standaard gebeurtenis | `change` | Verzoek wanneer waarde definitief is gewijzigd | `select`, `checkbox`, invoer na blur | `hx-trigger="change"` | | Standaard gebeurtenis | `submit` | Verzoek bij formulierinzending | Formulierverzending | `hx-trigger="submit"` | | Standaard gebeurtenis | `keyup` | Verzoek wanneer toets wordt losgelaten | Zoeken op basis van toetsinvoer, snelle reactie | `hx-trigger="keyup delay:500ms"` | | Standaard gebeurtenis | `keydown` | Verzoek op het moment dat een toets wordt ingedrukt | Hotkeys, toetsenbordinteractie | `hx-trigger="keydown[from:body]"` | | Standaard gebeurtenis | `mouseup` | Verzoek wanneer muisknop wordt losgelaten | Reactie na slepen/selecteren | `hx-trigger="mouseup"` | | [[HTMX]]-specifiek | `load` | Verzoek zodra element is geladen | Uitgesteld laden, initiële gegevens vullen | `hx-trigger="load"` | | [[HTMX]]-specifiek | `revealed` | Verzoek wanneer element op scherm verschijnt | Oneindig scrollen, lazy loading | `hx-trigger="revealed"` | | [[HTMX]]-specifiek | `intersect` | Verzoek wanneer element kruist met viewport | Nauwkeuriger lazy loading, scroll-gebaseerd laden | `hx-trigger="intersect once"` | | [[HTMX]]-specifieke syntaxis | `every 5s` | Verzoek met een vast interval | Polling, statusupdate | `hx-trigger="every 5s"` | | Aangepaste gebeurtenis | `my-custom-event` | Verzoek met een zelfgedefinieerde gebeurtenis | Serverheader, JS-integratie, losse gebeurtenisarchitectuur | `hx-trigger="itemSaved from:body"` | | Modifier | `delay:500ms` | Verzoek alleen als er gedurende de opgegeven tijd geen extra gebeurtenissen zijn | Debouncing, optimalisatie realtime zoeken | `hx-trigger="keyup delay:500ms"` | | Modifier | `throttle:1s` | Beperkt herhaalde verzoeken binnen een korte tijd | Voorkomen van dubbelklikken, beperken van overmatige verzoeken | `hx-trigger="click throttle:1s"` | | Modifier | `once` | Beperkt tot één keer triggeren | Eerste lading, eenmalige gebeurtenissen | `hx-trigger="intersect once"` | | Modifier | `changed` | Verzoek alleen als waarde daadwerkelijk is gewijzigd | Optimalisatie invoervelden, voorkomen van onnodige verzoeken | `hx-trigger="input changed delay:500ms"` | | Modifier | `from:body` | Specificeert een ander element als doel voor gebeurtenisdetectie | Globale gebeurtenissen ontvangen, aangepaste gebeurtenisverwerking | `hx-trigger="itemSaved from:body"` | | Modifier | `[condition]` | Verzoek alleen als aan de voorwaarde is voldaan | Combinatie van modificatietoetsen, voorwaarde voor invoerlengte | `hx-trigger="click[ctrlKey]"` / `hx-trigger="keyup[value.length > 1]"` | | Modifier | `consume` | Voorkomt dat de gebeurtenis wordt doorgegeven aan bovenliggende elementen | Voorkomen van conflicten bij geneste [[HTMX]]-verzoeken | `hx-trigger="click consume"` | | Modifier | `queue:first` | Behoudt alleen de eerste gebeurtenis bij het in de wachtrij plaatsen van nieuwe gebeurtenissen | Alleen het eerste verzoek behouden bij opeenvolgende invoer | `hx-trigger="input queue:first"` | | Modifier | `queue:last` | Behoudt alleen de laatste gebeurtenis bij het in de wachtrij plaatsen van nieuwe gebeurtenissen | Zoekbalk, auto-aanvullen | `hx-trigger="input queue:last"` | | Modifier | `queue:all` | Behoudt alle 발생한 gebeurtenissen in de wachtrij | Wanneer alle gebeurtenissen sequentieel moeten worden verwerkt | `hx-trigger="input queue:all"` | | Modifier | `queue:none` | Negeert nieuwe gebeurtenissen als er een verzoek bezig is | Volledige blokkering van dubbele verzoeken | `hx-trigger="click queue:none"` | De waarde van `hx-trigger` bestaat meestal uit een **gebeurtenis (event)**, gevolgd door eventuele **filters** en **modifiers**. Je kunt het lezen als: **"wanneer er iets gebeurt (event), onder welke voorwaarde (filter), en op welke manier (modifier) moet het worden afgehandeld?"** De vorm is meestal `event[filter] modifier modifier`. ```html ``` - `keyup` → Wanneer een toets wordt losgelaten - `[value.length > 1]` → Alleen wanneer de invoerwaarde langer is dan 1 teken - `changed delay:500ms` → Verzoek alleen als de waarde is gewijzigd en er gedurende 0,5 seconde geen verdere invoer is geweest ## Enkele nuttige voorbeelden {#sec-d893c37bc6f7} Hoewel de bovenstaande tabel een goed overzicht geeft, wil ik graag enkele van mijn favoriete trigger-voorbeelden laten zien. ### Verzoek alleen verzenden nadat invoer is gestopt: `delay` {#sec-cd31c7256394} Wanneer je functies zoals auto-aanvullen in zoekbalken of realtime filtering maakt, kan het verzenden van een verzoek bij elke typslag de server belasten en de gebruikerservaring onrustig maken. In dergelijke gevallen maakt het gebruik van `delay` de ervaring veel vloeiender. ```html ``` Deze code verzendt niet direct een verzoek bij elke toetsaanslag van de gebruiker. In plaats daarvan wordt het verzoek verzonden **nadat de invoer is gestopt en er 500ms zijn verstreken**. Dit is in feite **debouncing**. Om dit met JavaScript te implementeren, heb je code nodig die timers instelt, eerdere timers annuleert en opnieuw configureert. Maar met [[HTMX]] is dit eenvoudigweg een attribuut. Deze functionaliteit is vrijwel essentieel voor zoek-, auto-aanvul- en filter-UI's. --- ### Niet te vaak verzenden: `throttle` {#sec-c84ae134ee88} Terwijl `delay` het gevoel geeft van "even wachten nadat de invoer is gestopt, en dan verzenden", ligt `throttle` dichter bij "het beperken van te frequente verzoeken binnen een korte tijd". ```html ``` In dit geval, zelfs als de gebruiker heel snel meerdere keren op de knop klikt, kun je voorkomen dat er binnen 1 seconde overmatig veel opeenvolgende verzoeken worden verzonden. Dit is vrij nuttig in de volgende situaties: - Voorkomen van dubbelklikken - Blokkeren van te snelle herhaalde verzoeken - Verminderen van serverbelasting - Voorkomen van onbedoelde meervoudige uitvoering van dezelfde actie Vooral bij knoppen zoals "Vind ik leuk", "Opslaan", "Vernieuwen" en "Synchroniseren" is dit iets om te overwegen. --- ### Automatisch verzoeken met een vast interval: `every` {#sec-0195e4e0d263} Een functie die verrassend aantrekkelijk is bij het gebruik van [[HTMX]] is `every`. Wanneer je een specifiek gebied met een vast interval van de server wilt vernieuwen, hoef je geen aparte polling-logica in JavaScript te schrijven. ```html