Une mise à jour partielle automatique avec Alpine.js et HTMX (Français (French))

Une mise à jour partielle automatique avec Alpine.js et 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

Présentation

Donc dans ce qui devient une série, dans un projet de travail je voulais ajouter la capacité d'une partie à auto-mise à jour sur une échelle de temps donnée.

Voici comment je l'ai fait en utilisant Alpine.js et HTMX.

Besoins

Donc je voulais que ce soit

  1. réutilisable; il devrait donc être assez simple et autonome pour permettre la mise à jour automatique de n'importe quel élément.
  2. Il devrait respecter les paramètres Url existants
  3. Il devrait être détectable côté serveur (dans ASP.NET Core dans cette instance)
  4. Si elle est activée, elle doit être activée. pour ce critère d'évaluation Seulement et cela doit être rappelé entre les demandes.
  5. Il devrait faire instantanément la mise à jour lorsque activé (de sorte que l'utilisateur sait à quoi il ressemble)
  6. Il devrait pouvoir être désactivé par l'utilisateur
  7. Il devrait être simple d'inclure dans une page.

Dans cette optique, j'ai entrepris de construire un petit module JS en utilisant Alpine.js et HTMX.

REMARQUE

Vous pouvez faire des mises à jour automatiques des fonctionnalités « on and off » et « remember » assez simplement avec HTMX seul. Par exemple, en utilisant Déclencheurs HTMX Tu peux vraiment faire beaucoup de choses.


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

Grâce à @KhalidAbuhakmeh pour avoir signalé ça.

Ce code utilise en fait hx-trigger pour mettre en place la mise à jour automatique. Il suffit d'utiliser Alpine.js pour configurer les attributs HTMX.

Ce que cela ajoute vraiment est le côté client de l'interaction utilisateur, ce qui est ce que Alpine.js est excellent.

Le Code

Le code pour cela est vraiment assez compact, il est divisé en deux parties principales : un module JS, les gestionnaires d'événements et le HTML.

Le module

Le module est un simple module JS qui utilise Alpine.js pour gérer l'état de la mise à jour automatique. Il utilise le stockage local pour se souvenir de l'état de la mise à jour automatique entre les requêtes.

Il accepte les params :

  • endpointId - l'identifiant de l'élément à mettre à jour
  • actionUrl - l'url à appeler pour mettre à jour l'élément
  • initialInterval - l'intervalle initial à utiliser pour la mise à jour automatique (par défaut 30 secondes)

Nous pouvons également voir qu'il utilise quelques touches ; celles-ci sont utilisées pour le stockage local pour se souvenir de l'état de la mise à jour automatique. Vous pouvez voir que j'utilise le actionurl en tant que partie de la clé pour rendre ce paramètre spécifique.

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() Méthode

Cette méthode permet ou désactive le sondage automatique d'un élément HTML cible à l'aide de HTMX.

Comportement

  • Sélectionne un élément par son endpointId.
  • Construise l'URL de la requête (fullUrl) en combinant les données suivantes: actionUrl avec la chaîne de requête de la page actuelle.
  • Vérifie si le vote a été précédemment activé en lisant à partir de localStorage (bien qu'il soit rappelé entre les sessions du navigateur).

Quand this.autoUpdate est true (c'est-à-dire que le scrutin est activé) :

  • Définit les attributs HTMX sur l'élément :
    • hx-trigger de procéder à des sondages interval secondes
    • hx-swap="innerHTML" pour remplacer le contenu de l'élément
    • hx-get pour pointer vers l'URL du sondage
    • hx-headers pour ajouter une personnalisation "AutoPoll": "auto" en-tête
  • Enregistre l'état activé à localStorage
  • Appels htmx.process(el) pour permettre à HTMX de reconnaître les nouveaux attributs
  • Si elle était précédemment désactivée, déclenche immédiatement une requête HTMX via htmx.ajax() (ne s'appuyant pas sur le câblage d'événements HTMX)

Quand this.autoUpdate est false (c'est-à-dire que le scrutin est désactivé) :

  • Supprime les attributs HTMX ci-dessus
  • Efface le réglage enregistré de localStorage
  • Appels htmx.process(el) à nouveau pour mettre à jour le comportement HTMX

Sondage automatique lorsqu'il est activé pour la première fois

Nous avons également une branche ici pour effectuer la pollinisation automatique quand elle est activée pour la première fois.

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

Ceci effectue une requête HTMX à la fullUrl et met à jour l'élément cible avec la réponse. Ceci est utile pour montrer à l'utilisateur à quoi ressemblera l'auto-update quand ils l'activeront.

En-têtes

Vous noterez que nous envoyons également un en-tête HTMX avec la requête. Ceci est important car il nous permet de détecter le côté serveur de requête.

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

Dans mon côté serveur, je détecte ensuite cet en-tête en utilisant

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

Tu verras que je cherche juste l'en-tête avec Request.Headers.TryGetValue("AutoPoll", out _) Et si c'est là, je sais que c'est une demande d'autopoll.

J'attrape ensuite le Yime actuel (c'est pour un client français, donc je me convertis à l'heure de Paris) et je porte un toast avec l'heure.

AfficherToast

Les ShowToast méthode est une méthode d'extension simple qui définit un déclencheur pour dire à HTMX de montrer un message toast.

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

    }

Ceci est ensuite détecté par mon composant HTMX toast qui affiche le message.

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

Ceci appelle alors dans mon composant Toast I écrit à propos d'ici .

Je l'accroche.

Il est assez simple de brancher ce module vers le haut, dans votre main.js \ index.js tout ce qui vient de l'importer et le brancher à la fenêtre

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

Nous appelons ensuite la méthode init dans le code ASP.NET Razor:

Code du rasoir ASP.NET

Pour le rendre aussi petit et réutilisable que possible, le code Razor est assez simple.

Ici vous pouvez voir que je spécifie les attributs de données Alpine.js pour configurer l'auto-update.

  • x-data: C'est là que nous avons configuré l'objet de données Alpine.js.
  • x-init: C'est là que nous appelons la méthode init sur le contrôleur de mise à jour automatique.
  • x-on:change: C'est là que nous appelons la méthode toggleAutoUpdate sur le contrôleur de mise à jour automatique.
  • data-endpoint-id: C'est l'id de l'élément à mettre à jour.
  • data-action-url: C'est l'url à appeler pour mettre à jour l'élément.
  • interval de données: C'est l'intervalle à utiliser pour la mise à jour automatique (par défaut est de 30 secondes).

Vous verrez que nous définissons la cible à utiliser pour la requête à la campaignemail-request-list élément. C'est l'élément qui sera mis à jour avec le nouveau contenu. C'est alors inclus quelque part dans la page.

Maintenant, lorsqu'une case à cocher est cochée, la liste sera automatiquement mise à jour toutes les 30 secondes.

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

En conclusion

Et c'est tout, assez simple. En utilisant HTMX et Alpine.js pour créer un simple composant de mise à jour automatique, nous pouvons facilement utiliser ASP.NET Core.

logo

©2024 Scott Galloway