Een Auto-Update Partiële Updater met Alpine.js en HTMX (Nederlands (Dutch))

Een Auto-Update Partiële Updater met Alpine.js en HTMX

Comments

NOTE: Apart from English (and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.

Wednesday, 23 April 2025

//

Less than a minute

Inleiding

Dus in wat een serie wordt, in een werkproject wilde ik de mogelijkheid toevoegen voor een gedeeltelijke auto-update op een bepaalde tijdsperiode.

Zo heb ik het gedaan met Alpine.js en HTMX.

Vereisten

Dus ik wilde dat dit zou zijn

  1. herbruikbaar; dus het moet eenvoudig en zelfstandig genoeg zijn om elk element automatisch te updaten.
  2. Het dient bestaande Url-parameters in acht te nemen
  3. Het moet detecteerbaar zijn Server Side (in ASP.NET Core in dit geval)
  4. Indien ingeschakeld dient deze ingeschakeld te zijn voor dat eindpunt alleen en dit moet worden onthouden tussen de verzoeken.
  5. Het moet direct de update doen als het is ingeschakeld (dus de gebruiker weet hoe het eruit ziet)
  6. Het moet kunnen worden uitgeschakeld door de gebruiker
  7. Het zou eenvoudig moeten zijn om in een pagina op te nemen.

Met dit in het achterhoofd wilde ik een kleine JS module bouwen met behulp van Alpine.js en HTMX.

NOOT

U kunt de 'aan en uit' en 'herinner' functies automatisch updaten met alleen HTMX. Bijvoorbeeld; met behulp van HTMX-triggers Je kunt echt veel dingen doen.


<div id="campaignemail-request-list" hx-get="@Url.Action("List", "CampaignEmailRequest")" hx-trigger="every 30s" hx-swap="innerHTML">
    <partial name="_List" model="@Model"/>
</div>

Dankzij @KhalidAbuhakmeh voor het aanwijzen van dit.

Deze code gebruikt in feite hx-trigger om de auto-update op te zetten. Gewoon met Alpine.js om de HTMX attributen te configureren.

Wat dit echt toevoegt is de gebruiker interactie client kant; dat is waar Alpine.js is geweldig in.

De code

De code voor dit is echt vrij compact, het is opgedeeld in twee hoofdonderdelen; een JS module, de event handlers en de HTML.

De module

De module is een eenvoudige JS module die Alpine.js gebruikt om de staat van de auto-update te beheren. Het gebruikt lokale opslag om de staat van de auto-update tussen verzoeken te onthouden.

Het accepteert de params :

  • endpointId - de id van het bij te werken element
  • actionUrl - de url die aangeroepen moet worden om het element bij te werken
  • initialInterval - het initiële interval voor de auto-update (standaard is 30 seconden)

We kunnen ook zien dat het een paar sleutels gebruikt; deze worden gebruikt voor lokale opslag om de staat van de auto-update te onthouden. U kunt zien dat ik gebruik maken van de actionurl als onderdeel van de sleutel om dit eindpunt specifiek te maken.

export function autoUpdateController(endpointId, actionUrl, initialInterval = 30) {
const keyPrefix = `autoUpdate:${actionUrl}`;
const enabledKey = `${keyPrefix}:enabled`;

    return {
        autoUpdate: false,
        interval: initialInterval,

        toggleAutoUpdate() {
            const el = document.getElementById(endpointId);
            if (!el) return;

            const url = new URL(window.location.href);
            const query = url.searchParams.toString();
            const fullUrl = query ? `${actionUrl}?${query}` : actionUrl;

            const wasPreviouslyEnabled = localStorage.getItem(enabledKey) === 'true';

            if (this.autoUpdate) {
                el.setAttribute('hx-trigger', `every ${this.interval}s`);
                el.setAttribute('hx-swap', 'innerHTML');
                el.setAttribute('hx-get', fullUrl);
                el.setAttribute('hx-headers', JSON.stringify({ AutoPoll: 'auto' }));

                localStorage.setItem(enabledKey, 'true');

                htmx.process(el); // rebind with updated attributes
                
                if (!wasPreviouslyEnabled) {
                    htmx.ajax('GET', fullUrl, {
                        target: el,
                        swap: 'innerHTML',
                        headers: {AutoPoll: 'auto'}
                    });
                }
            } else {
                el.removeAttribute('hx-trigger');
                el.removeAttribute('hx-get');
                el.removeAttribute('hx-swap');
                el.removeAttribute('hx-headers');

                localStorage.removeItem(enabledKey);
                htmx.process(el);
            }
        },

        init() {
            this.autoUpdate = localStorage.getItem(enabledKey) === 'true';
            this.toggleAutoUpdate();
        }
    };
}

toggleAutoUpdate() Methode

Deze methode maakt automatische polling van een target HTML-element met behulp van HTMX mogelijk of schakelt deze uit.

Gedrag

  • Selecteert een element door zijn endpointId.
  • Bouwt de aanvraag-URL (fullUrl) door het combineren van de gegeven actionUrl met de huidige pagina's query string.
  • Controles of de peiling eerder was ingeschakeld door het lezen van localStorage (goed als het wordt onthouden tussen browser sessies).

Wanneer this.autoUpdate is true (d.w.z. de peiling is ingeschakeld):

  • Stelt HTMX-attributen in op het element:
    • hx-trigger om te peilen elke interval seconden
    • hx-swap="innerHTML" ter vervanging van de inhoud van het element
    • hx-get om te verwijzen naar de stembus URL
    • hx-headers om een aangepaste toe te voegen "AutoPoll": "auto" kop
  • Slaat de ingeschakelde status op naar localStorage
  • Oproepen htmx.process(el) om HTMX de nieuwe attributen te laten herkennen
  • Als het eerder uitgeschakeld was, activeert onmiddellijk een HTMX-verzoek via htmx.ajax() (niet afhankelijk van HTMX event bedrading)

Wanneer this.autoUpdate is false (d.w.z. de peiling is uitgeschakeld):

  • Verwijdert de bovenstaande HTMX-attributen
  • Wis de opgeslagen instelling van localStorage
  • Oproepen htmx.process(el) opnieuw om HTMX-gedrag bij te werken

Autopoll indien eerst ingeschakeld

We hebben hier ook een branch om de auto-poll uit te voeren wanneer dit voor het eerst is ingeschakeld.

const wasPreviouslyEnabled = localStorage.getItem(enabledKey) === 'true';
      if (!wasPreviouslyEnabled) {
                    htmx.ajax('GET', fullUrl, {
                        target: el,
                        swap: 'innerHTML',
                        headers: {AutoPoll: 'auto'}
                    });
                }

Dit voert een HTMX verzoek naar de fullUrl en actualiseert het doelelement met de reactie. Dit is handig voor het tonen van de gebruiker hoe de auto-update eruit zal zien wanneer ze het inschakelen.

Berichtkoppen

U zult merken dat we ook een HTMX header sturen met het verzoek. Dit is belangrijk omdat het ons in staat stelt om de request server kant te detecteren.

   el.setAttribute('hx-headers', JSON.stringify({ AutoPoll: 'auto' }));
headers: {AutoPoll: 'auto'}

In mijn serverzijde detecteer ik deze header die wordt ingesteld met behulp van

 if (Request.Headers.TryGetValue("AutoPoll", out _))
        {
            
            
            var utcDate = DateTime.UtcNow;
            var parisTz = TimeZoneInfo.FindSystemTimeZoneById("Europe/Paris");
            var parisTime = TimeZoneInfo.ConvertTimeFromUtc(utcDate, parisTz);

            var timeStr = parisTime.ToString("yyyy-MM-dd HH:mm:ss");
              Response.ShowToast($"Auto Update Last updated: {timeStr} (paris)",true); 
         
            return PartialView("_List", requests);
        }

Je zult zien dat ik gewoon naar de kop zoek met Request.Headers.TryGetValue("AutoPoll", out _) En als het daar is, weet ik dat het een autopoll verzoek is.

Ik pak dan de huidige yime (het is voor een Franse klant, dus ik bekeer me naar Parijs tijd) en toon een toast met de tijd.

Toast tonen

De ShowToast methode is een eenvoudige extensie methode die een trigger zet om HTMX te vertellen een toast bericht te tonen.

    public static void ShowToast(this HttpResponse response, string message, bool success = true)
    {
        response.Headers.Append("HX-Trigger", JsonSerializer.Serialize(new
        {
            showToast = new
            {
                toast = message,
                issuccess =success
            }
        }));

    }

Dit wordt dan gedetecteerd door mijn HTMX toast component die het bericht toont.

document.body.addEventListener("showToast", (event) => {
    const { toast, issuccess } = event.detail || {};
    const type = issuccess === false ? 'error' : 'success';
    showToast(toast || 'Done!', 3000, type);
});

Dit roept dan in mijn Toast component I schreef over hier .

Ik kook het op.

Het is vrij eenvoudig om deze module aan te koppelen, in je main.js \ index.js wat het ook maar importeert en koppelt het aan Window

import './auto-actions';

window.autoUpdateController = autoUpdateController; //note this isn't strictly necessary but it makes it easier to use in the HTML


//Where we actually hook it up to Alpine.js
document.addEventListener('alpine:init', () => {
    Alpine.data('autoUpdate', function () {
        const endpointId = this.$el.dataset.endpointId;
        const actionUrl = this.$el.dataset.actionUrl;
        const interval = parseInt(this.$el.dataset.interval || '30', 10); // default to 30s

        return autoUpdateController(endpointId, actionUrl, interval);
    });
});

Vervolgens noemen we de init methode in de ASP.NET Razor code:

ASP.NET Razor Code

Om dit zo klein en herbruikbaar mogelijk te maken is de Razor code vrij eenvoudig.

Hier kunt u zien dat ik de Alpine.js data attributen voor het instellen van de auto-update.

  • x-data: Hier zetten we het Alpine.js data object op.
  • x-init: Hier noemen we de init methode op de auto-update controller.
  • x-on:change: Hier noemen we de toggleAutoUpdate methode op de auto-update controller.
  • data-endpoint-id: Dit is de id van het element dat moet worden bijgewerkt.
  • data-action-url: Dit is de url die aangeroepen moet worden om het element bij te werken.
  • data-interval: Dit is het interval dat gebruikt moet worden voor de auto-update (standaard is 30 seconden).

U zult zien dat we het doel voor het verzoek aan de campaignemail-request-list element. Dit is het element dat zal worden bijgewerkt met de nieuwe inhoud. Dat is dan ergens in de pagina opgenomen.

Wanneer een selectievakje wordt aangevinkt, wordt de lijst elke 30 seconden automatisch bijgewerkt.

            <div class=" px-4 py-2 bg-base-100 border border-base-300 rounded-box"
                x-data="autoUpdate()" 
                x-init="init"
                x-on:change="toggleAutoUpdate"
                data-endpoint-id="campaignemail-request-list"
                data-action-url="@Url.Action("List", "CampaignEmailRequest")"
                data-interval="30"
                >
                <label class="flex items-center gap-2">
                    <input type="checkbox" x-model="autoUpdate" class="toggle toggle-sm" />
                    <span class="label-text">
                        Auto update every <span x-text="$data.interval"></span>s
                    </span>
                </label>
            </div>

        <!-- Voucher List -->
        <div id="campaignemail-request-container">
            <div
                id="campaignemail-request-list">
                <partial name="_List" model="@Model"/>
            </div>
        </div>

Conclusie

En dat is het, vrij eenvoudig rechts. Leveraging HTMX en Alpine.js om een eenvoudige auto-update component te maken die we gemakkelijk kunnen gebruiken van ASP.NET Core.

logo

©2024 Scott Galloway