This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Así que en lo que se está convirtiendo en una serie, en un proyecto de trabajo que quería añadir la capacidad de una parcial a la actualización automática en una escala de tiempo dada.
Así es como lo hice usando Alpine.js y HTMX.
Así que quería que esto fuera
Con esto en mente me propuse construir un pequeño módulo JS usando Alpine.js y HTMX.
Usted puede hacer actualizaciones automáticas sin las características 'on and off' y'remember' bastante simplemente con HTMX solo. Por ejemplo;usando Activadores HTMX Realmente puedes hacer un montón de cosas.
<div id="campaignemail-request-list" hx-get="@Url.Action("List", "CampaignEmailRequest")" hx-trigger="every 30s" hx-swap="innerHTML">
<partial name="_List" model="@Model"/>
</div>
Gracias a @KhalidAbuhakmeh por señalar esto.
Este código de hecho utiliza hx-trigger
para configurar la actualización automática. Simplemente usando Alpine.js para configurar los atributos HTMX.
Es por eso que HTMX con Alpine.js es una combinación tan poderosa; HTMX maneja toda la interacción del servidor y las peticiones AJAX, mientras que Alpine.js maneja el estado e interacción del lado del cliente. ¿Podrías también hacer esto en Vanilla JS? Claro, pero terminas escribiendo un montón de código para hacer lo mismo que estas dos bibliotecas TINY ya hacen.
El código para esto es bastante compacto, se divide en dos partes principales: un módulo JS, los manejadores de eventos y el HTML.
El módulo es un simple módulo JS que utiliza Alpine.js para gestionar el estado de la actualización automática. Utiliza almacenamiento local para recordar el estado de la actualización automática entre solicitudes.
Acepta los parámetros:
endpointId
- el id del elemento a actualizaractionUrl
- la url a llamar para actualizar el elementoinitialInterval
- el intervalo inicial que se utilizará para la actualización automática (por defecto es de 30 segundos)También podemos ver que utiliza un par de teclas; estas se utilizan para el almacenamiento local para recordar el estado de la actualización automática.
Usted puede ver que yo uso el actionurl
como parte de la clave para hacer este punto final específico.
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étodoEste método permite o deshabilita la votación automática de un elemento HTML de destino usando HTMX.
endpointId
.fullUrl
) mediante la combinación de las actionUrl
con la cadena de consulta de la página actual.localStorage
(bueno como se recuerda entre las sesiones del navegador).this.autoUpdate
es true
(es decir, la votación está habilitada):hx-trigger
para encuestar cada interval
segundoshx-swap="innerHTML"
para sustituir el contenido del elementohx-get
para apuntar a la URL de votaciónhx-headers
para añadir una costumbre "AutoPoll": "auto"
encabezadolocalStorage
htmx.process(el)
para que HTMX reconozca los nuevos atributoshtmx.ajax()
(no depende del cableado de eventos HTMX)this.autoUpdate
es false
(es decir, la votación está inhabilitada):localStorage
htmx.process(el)
de nuevo para actualizar el comportamiento de HTMXTambién tenemos una rama aquí para realizar el auto-poll cuando se habilitó por primera vez.
const wasPreviouslyEnabled = localStorage.getItem(enabledKey) === 'true';
if (!wasPreviouslyEnabled) {
htmx.ajax('GET', fullUrl, {
target: el,
swap: 'innerHTML',
headers: {AutoPoll: 'auto'}
});
}
Esto realiza una solicitud HTMX a la fullUrl
y actualiza el elemento objetivo con la respuesta. Esto es útil para mostrar al usuario cómo será la actualización automática cuando lo habilitan.
Notará que también enviamos un encabezado HTMX con la solicitud. Esto es importante, ya que nos permite detectar el lado del servidor de peticiones.
el.setAttribute('hx-headers', JSON.stringify({ AutoPoll: 'auto' }));
headers: {AutoPoll: 'auto'}
En el lado de mi servidor detecto que este encabezado está siendo configurado usando
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);
}
Ya verás que sólo busco la cabecera con Request.Headers.TryGetValue("AutoPoll", out _)
Y si está ahí sé que es una petición de auto-poll.
Luego tomo el yime actual (es para un cliente francés, así que me convierto a la hora de París) y muestro un brindis con el tiempo.
Los ShowToast
método es un método de extensión simple que establece un disparador para decirle a HTMX que muestre un mensaje de brindis.
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
}
}));
}
Esto es detectado por mi componente de tostada HTMX que muestra el mensaje.
document.body.addEventListener("showToast", (event) => {
const { toast, issuccess } = event.detail || {};
const type = issuccess === false ? 'error' : 'success';
showToast(toast || 'Done!', 3000, type);
});
Esto entonces llama a mi componente Tostada I escribió sobre aquí .
Es bastante simple conectar este módulo, en su main.js \ index.js lo que sea que sólo importarlo y conectarlo a la ventana
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);
});
});
Luego llamamos al método init en el código ASP.NET Razor:
Para hacer esto tan pequeño y reutilizable como sea posible el código Razor es bastante simple.
Aquí puede ver que especifico los atributos de datos Alpine.js para configurar la actualización automática.
Verá que establecemos el objetivo a utilizar para la solicitud a la campaignemail-request-list
elemento. Este es el elemento que se actualizará con el nuevo contenido.
Eso se incluye en alguna parte de la página.
Ahora, cuando se marca una casilla de verificación, se actualizará automáticamente la lista cada 30 segundos.
<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>
Y eso es todo, bastante simple. Aprovechamiento de HTMX y Alpine.js para crear un simple componente de actualización automática que podemos utilizar fácilmente desde ASP.NET Core.