Auto-Update Partial Updater mit Alpine.js und HTMX (Deutsch (German))

Auto-Update Partial Updater mit Alpine.js und 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

Einleitung

In dem, was zu einer Serie wird, wollte ich in einem Arbeitsprojekt die Fähigkeit für einen Teil hinzufügen, Auto-Update auf einer bestimmten Zeitskala.

So habe ich es mit Alpine.js und HTMX gemacht.

Anforderungen

Also wollte ich, dass das so ist

  1. wiederverwendbar; so sollte es einfach und in sich geschlossen genug sein, um jedes Element automatisch zu aktualisieren.
  2. Sie sollte die bestehenden Url-Parameter berücksichtigen.
  3. Es sollte nachweisbar Server Side sein (in diesem Fall in ASP.NET Core)
  4. Wenn eingeschaltet, sollte es aktiviert werden für diesen Endpunkt nur und dies sollte zwischen den Anfragen in Erinnerung bleiben.
  5. Es sollte sofort das Update tun, wenn aktiviert (so dass der Benutzer weiß, wie es aussieht)
  6. Es sollte vom Benutzer ausgeschaltet werden können
  7. Es sollte einfach sein, in eine Seite aufzunehmen.

In diesem Sinne wollte ich ein kleines JS-Modul mit Alpine.js und HTMX bauen.

HINWEIS

Sie können Auto-Updates der 'on and off' und'remember' Funktionen ziemlich einfach mit HTMX allein. Zum Beispiel; mit HTMX-Trigger Du kannst wirklich viel tun.


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

Dank @KhalidAbuhakmeh dafür, dass ich darauf hingewiesen habe.

Dieser Code verwendet in der Tat hx-trigger um das Auto-Update einzurichten. Verwenden Sie Alpine.js, um die HTMX-Attribute zu konfigurieren.

Was dies wirklich ergänzt, ist die User-Interaktion Client-Seite; das ist, was Alpine.js ist großartig.

Der Code

Der Code dafür ist wirklich ziemlich kompakt, er ist in zwei Hauptteile aufgeteilt: ein JS-Modul, die Event-Handler und das HTML.

Das Modul

Das Modul ist ein einfaches JS-Modul, das mit Alpine.js den Zustand des Auto-Updates verwaltet. Es verwendet lokalen Speicher, um den Zustand des Auto-Update zwischen Anfragen zu speichern.

Es akzeptiert die Parameter:

  • endpointId - die ID des zu aktualisierenden Elements
  • actionUrl - die URL, die aufgerufen werden soll, um das Element zu aktualisieren
  • initialInterval - das für das Auto-Update zu verwendende Anfangsintervall (Standard ist 30 Sekunden)

Wir können auch sehen, dass es ein paar Schlüssel verwendet; diese werden für den lokalen Speicher verwendet, um den Zustand des Auto-Updates zu speichern. Sie können sehen, dass ich die actionurl als Teil des Schlüssels, um diesen Endpunkt spezifisch zu machen.

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() Verfahren

Diese Methode ermöglicht oder deaktiviert die automatische Abfrage eines Ziel-HTML-Elements mit HTMX.

Verhalten

  • Wählt ein Element durch seine endpointId.
  • Baut die Request-URL (fullUrl) durch Kombination der angegebenen actionUrl mit dem Abfrage-String der aktuellen Seite.
  • Überprüft, ob das Polling zuvor durch Lesen von localStorage (gut, wie es zwischen den Browser-Sitzungen erinnert wird).

Wann this.autoUpdate wird true (d.h. Umfragen sind aktiviert):

  • Setzt HTMX-Attribute auf das Element:
    • hx-trigger zu jeder Umfrage interval Sekunden
    • hx-swap="innerHTML" den Inhalt des Elements zu ersetzen
    • hx-get um auf die Umfrage-URL zu verweisen
    • hx-headers um einen Custom hinzuzufügen "AutoPoll": "auto" Kopfzeile
  • Speichert den aktivierten Zustand localStorage
  • Ausschreibungen htmx.process(el) HTMX die neuen Attribute erkennen lassen
  • Wenn es zuvor aus war, löst sofort eine HTMX-Anfrage über htmx.ajax() (nicht auf HTMX-Ereignisverkabelung angewiesen)

Wann this.autoUpdate wird false (d.h. Umfragen sind deaktiviert):

  • Entfernt die obigen HTMX-Attribute
  • Löscht die gespeicherte Einstellung aus localStorage
  • Ausschreibungen htmx.process(el) wieder zum Aktualisieren des HTMX-Verhaltens

Automatische Umfrage, wenn zuerst aktiviert

Wir haben auch einen Zweig hier, um das Auto-Poll durchzuführen, wenn zuerst aktiviert.

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

Dies führt eine HTMX-Anfrage an die fullUrl und aktualisiert das Zielelement mit der Antwort. Dies ist nützlich, um dem Benutzer zu zeigen, wie das Auto-Update aussehen wird, wenn sie es aktivieren.

Kopfzeilen

Sie werden feststellen, dass wir auch einen HTMX-Header mit der Anfrage senden. Dies ist wichtig, da es uns erlaubt, die Request-Server-Seite zu erkennen.

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

Auf meiner Serverseite erkenne ich dann, dass dieser Header mit

 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);
        }

Du wirst sehen, ich suche einfach nach dem Header mit Request.Headers.TryGetValue("AutoPoll", out _) Und wenn es da ist, weiß ich, dass es eine Autopoll-Anfrage ist.

Ich nehme dann das aktuelle Yime (es ist für einen französischen Kunden, also bekehre ich mich in Paris Zeit) und zeige einen Toast mit der Zeit.

Toast anzeigen

Das ShowToast Methode ist eine einfache Erweiterungsmethode, die einen Trigger setzt, um HTMX zu sagen, eine Toast-Nachricht anzuzeigen.

    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
            }
        }));

    }

Dies wird dann von meiner HTMX Toast-Komponente erkannt, die die Meldung anzeigt.

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

Dies ruft dann in meine Toast-Komponente I schrieb über hier .

Ich hänge es an.

Es ist ziemlich einfach, dieses Modul zu verbinden, in Ihrem main.js \ index.js was immer es gerade importieren und es an Fenster anschließen

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);
    });
});

Wir rufen dann die init-Methode im ASP.NET-Razor-Code auf:

ASP.NET-Razor-Code

Um dies so klein und wiederverwendbar wie möglich zu machen, ist der Razor-Code ziemlich einfach.

Hier sehe ich die Datenattribute Alpine.js, um das Auto-Update einzurichten.

  • x-data: Hier haben wir das Datenobjekt Alpine.js eingerichtet.
  • x-init: Hier nennen wir die init-Methode auf dem Auto-Update-Controller.
  • x-on:change: Hier rufen wir die ToggleAutoUpdate Methode auf dem Auto-Update Controller auf.
  • data-endpoint-id: Dies ist die ID des zu aktualisierenden Elements.
  • data-action-url: Dies ist die URL, die aufgerufen werden soll, um das Element zu aktualisieren.
  • Daten-Intervall: Dies ist das Intervall, das für das Auto-Update verwendet werden soll (Standard ist 30 Sekunden).

Sie werden sehen, wir setzen das Ziel für die Anfrage zu verwenden, um die campaignemail-request-list .............................................................................................................................................. Dies ist das Element, das mit dem neuen Inhalt aktualisiert wird. Das ist dann enthalten SOMEWHERE in der Seite.

Wenn nun ein Kontrollkästchen aktiviert ist, wird die Liste automatisch alle 30 Sekunden aktualisiert.

            <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>

Schlussfolgerung

Und das war's, ganz einfach richtig. Mithilfe von HTMX und Alpine.js erstellen wir eine einfache Auto-Update-Komponente, die wir problemlos von ASP.NET Core nutzen können.

logo

©2024 Scott Galloway