En Auto-Update Partiell Updater med Alpine.js och HTMX
Inleiding
Så i vad som blir en serie- -, i ett arbetsprojekt ville jag lägga till möjligheten att göra en del- -automatiskt- -update på en given tidsskala.
Här är hur jag gjorde det med Alpine.
Benötningar
Så jag ville att detta skulle vara
- återanvändbar; så att det ska vara enkelt och självständigt
- Det borde respektera de existerande Url-parameterna
- Den borde vara upptäckbar på serversidan (i ASP.NET Core i detta fallet )
- Om den är aktiverad borde den aktiveras för den slutpunkten bara och detta bör komma ihåg mellan begäran
- Den borde göra uppgraderingen omedelbart när den är aktiverad ( så att användaren vet hur den ser ut
- Den borde kunna stängas av av av användaren
- Det borde vara enkelt att inkludera på en sida.
Med detta i åtanke bestämde jag mig för att bygga ett litet JS-modul med Alpine.js och HTMX.
NOTA
Du kan göra automatiska uppdaterade system utan att behöva ' på och av' och ' komma ihågM SK3 egenskaper på ett ganska enkelt sätt bara med HTMX Till exempel; med HTMX Sneller du kan verkligen göra en massa saker
<div id="campaignemail-request-list" hx-get="@Url.Action("List", "CampaignEmailRequest")" hx-trigger="every 30s" hx-swap="innerHTML">
<partial name="_List" model="@Model"/>
</div>
Tack till @KhalidAbuhakmeh för att peka ut detta.
Denna kod använder faktiskt hx-trigger att installera den automatiska versionen.
Det är därför HTMX med Alpine.js är en så kraftfull kombination ; HT MX hanterar alla serverinteraktioner och AJAX-inlärningar , medan Alpine~.js hanterar klientseitiga tillstånd och interaktioner M SK5 Kan du också göra det här i Vanilla JS?
Koden
Koden för detta är verkligen ganska kompakt.
Modulet
Modulet är ett enkelt JS-modul som använder Alpine.js för att sköta tillståndet på den automatiserade versionen
Den accepterar fraserna :
endpointId- ID av elementet som ska uppdaterasactionUrl- url som ska kallas för att uppdatera elementetinitialInterval- det initiala intervallet som skall användas för den automatiserade versionen
Vi kan också se att den använder ett par nycklar; som används för plats lagring för att komma ihåg tillståndet på den automatiserade versionen
Ni kan se att jag använder actionurl som en del av nyckeln till att göra detta slutpunkt specifikt.
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() Metod
Den här metoden aktiverar eller avsperar automatisk rösting på ett HTML element med hjälp av HTMX.
Vanor
- Väljer ett element genom dess
endpointId. - Bygger upp begäran URL (
fullUrl) genom att kombinera den gedaactionUrlmed den nuvarande sidan's söktråd. - Ser om folkröstning tidigare aktiverats genom att läsa från
localStorage(bra eftersom det kommer ihågs mellan webblader sessioner).
När this.autoUpdate är true (, i, ., e, M SK2, folkröstning är aktiverad
- Inser HTMX-attribute på elementet:
hx-triggeratt rösta på varjeintervalsekunderhx-swap="innerHTML"för att ersätta elementet’s innehållhx-getför att peka på röstsedelns URLhx-headersatt lägga till en anpassad"AutoPoll": "auto"header
- sparar den aktiverade tillståndet till
localStorage - Rörningar
htmx.process(el)att låta HTMX känna igen de nya egenskaperna - Om den tidigare var avstängd, triggar den omedelbart en HTMX-fråga via
htmx.ajax()( inte förlitar sig på HTMX-inspelning
När this.autoUpdate är false (, i, ., e, M SK2, rösting är avstängd
- Removerar de tidigare HTMX-attributena
- Klarar sparade inställningarna från
localStorage - Rörningar
htmx.process(el)att uppdatera HTMX-beteende igen
Automatisk Poll när den först aktiveras
Vi har också en gren här för att utföra automatiseringen.
const wasPreviouslyEnabled = localStorage.getItem(enabledKey) === 'true';
if (!wasPreviouslyEnabled) {
htmx.ajax('GET', fullUrl, {
target: el,
swap: 'innerHTML',
headers: {AutoPoll: 'auto'}
});
}
Detta utför en HTMX- begäran till fullUrl och uppdaterar målelementet med svaret. Det är användbart för att visa till användaren hur det kommer att se ut i automatiseringen när de aktiverar den
Påskriftar
Ni kommer att lägga märke till att vi även skickar en HTMX-Header med begäran. Detta är viktigt eftersom det tillåter oss att upptäcka begäran serversidan.
el.setAttribute('hx-headers', JSON.stringify({ AutoPoll: 'auto' }));
headers: {AutoPoll: 'auto'}
På min server sida upptäcker jag att den här headern ställs med
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);
}
Ni ' ser att jag bara letar efter rubriken med Request.Headers.TryGetValue("AutoPoll", out _) och om det är där, så vet jag att det är en automatiserad fråga.
Jag tar sedan den nuvarande yimen (it 's för en fransk kundM SK2 så jag konverterar till Paristid) och visar en toast med tiden
ShowToast
Den ShowToast metod är en enkel förlängningsmetod som sätter en aktivator för att säga till HTMX att visa ett toast meddelande.
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
}
}));
}
Detta upptäcks sedan av min HTMX toastkomponent som visar meddelandet.
document.body.addEventListener("showToast", (event) => {
const { toast, issuccess } = event.detail || {};
const type = issuccess === false ? 'error' : 'success';
showToast(toast || 'Done!', 3000, type);
});
Det här låter in i min brödkomponent I skrev om det här .
Att häcka upp det
Det är ganska enkelt att koppla upp den här modulen, ,, i din huvudversion. ., js, \ index, M SK4, JS vad som helst, bara importera den och ansluta den till Windows
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);
});
});
Sedan kallar vi init-metoden i ASP
ASP.NET Razor kod
För att göra detta så litet och återanvändbart som möjligt är koden för Razor ganska enkel.
Här kan ni se att jag specifikerar Alpine.js data-attributen för att sätta upp den automata
- x-data: Det här är där vi sätter upp Alpine dataobjektet
- x-init: Det här är där vi kallar init-metoden på den automata
- x- påM SK1 förändring : Det här är där vi kallar för toggleAutoUpdate-metoden på den automata
- data- slutpunkt-idM SK2 Detta är IDet för elementet som ska uppdateras
- data-actionM SK1url: Detta är url som ska kallas för att uppdatera elementet
- data-interval
Du' ser att vi har ställt målet att använda för begäran till campaignemail-request-list element. Detta är elementet som kommer att bli uppdaterat med den nya innehållet
Det "'" då inkluderades SOMMES på sidan
Nu när en checkbox är kontrollerad kommer den att automatiskt uppdatera listan varje 30 sekund
<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>
I slutsats
Och det är detta: HTMX och Alpine: .js används för att skapa en enkel automatiserad komponent som vi enkelt kan använda från ASP.