NOTE: Apart from
(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.
Saturday, 03 May 2025
//14 minute read
HTMX är ett kraftfullt JavaScript-bibliotek som låter dig skapa dynamiska webbapplikationer med minimal JavaScript. Det gör att du kan göra AJAX-förfrågningar, byta HTML-innehåll och hantera händelser direkt i dina HTML-attribut. Jag har använt HTMX i ungefär två år vid denna tidpunkt och med varje projekt lär jag mig mer och mer om dess kapacitet; och ännu viktigare är att det är begränsningar.
Som du kan se tillhandahåller HTMX ett antal händelser som du kan koppla in för att ändra begäran eller svar. Med hjälp av var och en av dessa kan du ändra hur HTMX interagerar med servern / klienten på ganska omfattande sätt.
En av de mest kraftfulla aspekterna av HTMX är förmågan att skapa utökningar Att utöka dess kapacitet. I mitt fall, jag vanligtvis krok in htmx:configRequest
lägga till ytterligare parametrar till begäran. Detta är användbart när du vill skicka ytterligare data till servern utan att behöva ändra HTML- eller JavaScript-koden.
Andra förlängningar kan kroka htmx:beforeRequest
ändra begäran innan den skickas, men efter de flesta andra förlängningar som krok configRequest
; som i beforeRequest
saker som HX-Vals
och HX-Include
s är redan fästa vid reuest (antingen i nyttolasten \ frågesträngen).
Du kan till och med kroka htmx:afterSwap
utföra åtgärder efter att innehållet har bytts ut. Kombinerat med klientsidan templating bibliotek som Alpina.js eller Stång av järn eller olegerat stål, varmvalsad, varmdragen eller varmsträngpressad men inte vidare bearbetad du kan skapa kraftfulla dynamiska applikationer med minimal kod.
HTMX ger några inbyggda tillägg som hx-boost
och hx-swap-oob
vilket gör att du kan förbättra funktionaliteten hos HTMX utan att skriva någon anpassad kod. Det finns dock tillfällen då du behöver skapa dina egna förlängningar för att uppfylla specifika krav.
Till exempel kanske du vill lägga till egna headers till dina önskemål, ändra begäran nyttolast, eller hantera specifika händelser på ett unikt sätt.
För att uppnå detta HTMX ger dig några praktiska integrationspunkter:
{
/**
* init(api)
* Called once when the extension is initialized.
* Use it to set up internal state, store references, or access HTMX utility functions via the api parameter.
*/
init: function(api) {
return null;
},
/**
* getSelectors()
* Returns additional CSS selectors that HTMX should monitor.
* Useful if your extension needs to handle custom elements or dynamic behavior.
*/
getSelectors: function() {
return null;
},
/**
* onEvent(name, evt)
* Called on every HTMX event (e.g., htmx:beforeRequest, htmx:afterSwap).
* Return false to cancel the event or stop propagation.
*/
onEvent: function(name, evt) {
return true;
},
/**
* transformResponse(text, xhr, elt)
* Modify the raw response text before it is parsed and swapped into the DOM.
* Use this to sanitize or preprocess HTML.
*/
transformResponse: function(text, xhr, elt) {
return text;
},
/**
* isInlineSwap(swapStyle)
* Return true if your extension will handle this swap style manually.
* This tells HTMX to skip default behavior.
*/
isInlineSwap: function(swapStyle) {
return false;
},
/**
* handleSwap(swapStyle, target, fragment, settleInfo)
* Perform custom DOM manipulation if you implement a custom swap style.
* Return true to prevent HTMX's default swap.
*/
handleSwap: function(swapStyle, target, fragment, settleInfo) {
return false;
},
/**
* encodeParameters(xhr, parameters, elt)
* Modify or serialize request parameters before sending.
* Return null to use default URL/form encoding.
* Return a string to override with a custom payload (e.g., JSON).
*/
encodeParameters: function(xhr, parameters, elt) {
return null;
}
}
HTMX tillhandahåller ett antal förbyggda tillägg som du kan Läs om här.
Till exempel en praktisk Inbyggd förlängning json-encode
låter dig skicka JSON data i begäran kroppen istället för URL-kodade formulär data. Detta är användbart när du vill skicka komplexa datastrukturer eller matriser till servern.
Du kan se att detta krokar in i 3 händelser
init
- att ställa in utökningen och lagra en hänvisning till HTMX APIonEvent
- för att ställa in Content-Type
Rubrik till application/json
när begäran är konfigureradencodeParameters
- att åsidosätta standard URL-kodad formulärkodning och serialisera parametrarna som JSON. Den returnerar också en sträng för att förhindra HTMX från att använda den förvalda URL-kodade formulärkodningen.(function() {
let api
htmx.defineExtension('json-enc', {
init: function(apiRef) {
api = apiRef
},
onEvent: function(name, evt) {
if (name === 'htmx:configRequest') {
evt.detail.headers['Content-Type'] = 'application/json'
}
},
encodeParameters: function(xhr, parameters, elt) {
xhr.overrideMimeType('text/json')
const object = {}
parameters.forEach(function(value, key) {
if (Object.hasOwn(object, key)) {
if (!Array.isArray(object[key])) {
object[key] = [object[key]]
}
object[key].push(value)
} else {
object[key] = value
}
})
const vals = api.getExpressionVars(elt)
Object.keys(object).forEach(function(key) {
// FormData encodes values as strings, restore hx-vals/hx-vars with their initial types
object[key] = Object.hasOwn(vals, key) ? vals[key] : object[key]
})
return (JSON.stringify(object))
}
})
})()
Eller till och med de enklare men ännu mer hångliga hx-debug
förlängning som lägger till en HX-Debug
Huvudet till begäran. Detta är användbart för felsökning och loggning, eftersom det gör att du kan se rå begäran och svarsdata i dev-konsolen.
(function() {
htmx.defineExtension('debug', {
onEvent: function(name, evt) {
if (console.debug) {
console.debug(name, evt)
} else if (console) {
console.log('DEBUG:', name, evt)
} else {
throw new Error('NO CONSOLE SUPPORTED')
}
}
})
})()
Det finns många fler, inklusive en mycket kraftfull utbyggnad av klientsidans templatering vilket gör att du kan använda klient-side templating bibliotek för att omvandla returnerade JSON data till HTML. Detta är användbart för att skapa dynamiska användargränssnitt utan att behöva förlita sig på server-side rendering.
Till exempel i ett nytt projekt använde jag HTMX OOB-swappar för att uppdatera ett antal rader i en tabell. För att göra detta ville jag veta vilka rader som för närvarande visas i tabellen, så jag uppdaterade bara de rader som var synliga.
export default {
encodeParameters: function (xhr, parameters, elt) {
const ext = elt.getAttribute('hx-ext') || '';
if (!ext.split(',').map(e => e.trim()).includes('dynamic-rowids')) {
return null; // Use default behavior
}
const id = elt.dataset.id;
const approve = elt.dataset.approve === 'true';
const minimal = elt.dataset.minimal === 'true';
const single = elt.dataset.single === 'true';
const target = elt.dataset.target;
const payload = { id, approve, minimal, single };
if (approve && target) {
const table = document.querySelector(target);
if (table) {
const rowIds = Array.from(table.querySelectorAll('tr[id^="row-"]'))
.map(row => row.id.replace('row-', ''));
payload.rowIds = rowIds;
}
}
// Merge payload into the parameters object
Object.assign(parameters, payload);
return null; // Return null to continue with default URL-encoded form encoding
}
}
För att använda den måste vi lägga till tillägget till vår HTMX-konfiguration. Så i din ingångspunkt js-fil (förutsatt att du använder moduler; joy bör vara) kan du göra något sådant här:
import dynamicRowIds from "./dynamicRowIds"; // Load the file
htmx.defineExtension("dynamic-rowids", dynamicRowIds); // Register the extension
Sedan på vilket element du vill använda det på du kan lägga till hx-ext
attribut med värdet dynamic-rowids
.
<button
hx-ext="dynamic-rowids"
data-target="#my-table"
data-id="@Model.Id"
data-param1="true"
data-param2="false"
data-param3="@Model.Whatever"
hx-post
hx-controller="Contoller"
hx-action="Action"
>
<i class='bx bx-check text-xl text-white'></i>
</button>
Detta är en annan enkel HTMX förlängning, denna tid ansluten till htmx:configRequest
eftersom vi ändrar webbadressen innan begäran skickas. Denna förlängning är praktiskt om du använder frågesträng baserad filtrering etc. och du vill att vissa förfrågningar ska bevara befintliga filter medan andra inte (t.ex. namn och "startdatum" men inte "sida" eller "sort").
Detta är SIMILAR till men inte exakt samma som den befintliga HTMX-tillägg Prövningsparamor
Du kan se att vi krokar onEvent
för att lyssna på htmx:configRequest
händelse.
Då gör vi så här:
preserve-params-exclude
attribut från elementet (om det finns) och dela upp det i en rad nycklar för att utesluta (så vi inte lägga till dem i begäran)export default {
onEvent: function (name, evt) {
if (name !== 'htmx:configRequest') return;
const el = evt.detail.elt;
const excludeStr = el.getAttribute('preserve-params-exclude') || '';
const exclude = excludeStr.split(',').map(s => s.trim());
const currentParams = new URLSearchParams(window.location.search);
const newParams = new URLSearchParams(evt.detail.path.split('?')[1] || '');
currentParams.forEach((value, key) => {
if (!exclude.includes(key) && !newParams.has(key)) {
newParams.set(key, value);
}
});
evt.detail.path = evt.detail.path.split('?')[0] + '?' + newParams.toString();
return true;
}
};
Här använder jag det väsentliga HTMX.Net för sina taggars hjälpare. Såna som hx-controller
och hx-action
är tagghjälpare som genererar rätt HTMX-attribut för dig. Såväl som hx-route-<x>
för värden att passera i rutten. Detta är verkligen användbart eftersom det tillåter dig att använda C#-kod för att generera rätt värden för attributen istället för att behöva hårdkoda dem i din HTML.
Att vara en förlängning det är verkligen enkelt att använda:
Först måste vi lägga till tillägget till vår HTMX-konfiguration.
import preserveParams from './preserveParams.js';
htmx.defineExtension('preserve-params', preserveParams);
OBS: Du kommer att märka att standard HTMX-tilläggen använder "autoload"-metoden för att ladda förlängningen.
// Autoloading the extension and registering it
(function() {
htmx.defineExtension('debug', {
}
Detta är ett bra sätt att göra det på om du använder HTMX i en icke-modul miljö. Men om du använder moduler (som du bör vara) är det bättre att använda import
uttalande för att ladda förlängningen sedan uttryckligen registrera den mot din htmx
till exempel. Detta gör att du kan dra nytta av trädskakning och bara ladda förlängningar du behöver.
Sedan på ditt element kan du lägga till hx-ext
attribut med värdet preserve-params
och preserve-params-exclude
attribut med en kommaseparerad lista över parametrar som ska uteslutas från begäran.
<a class="btn-outline-icon"
hx-controller="MyController"
hx-action="MyAction"
hx-route-myparam="@MyParam"
hx-push-url="true"
hx-ext="preserve-params"
preserve-params-exclude="page,sort"
hx-target="#page-content"
hx-swap="innerHTML show:top"
hx-indicator>
<i class="bx bx-search"></i>
</a>
I detta fall på grund av event.detail.path
med den nya myparam
värde ställa in det i det kommer att ersätta den med vårt nya värde men bevara alla andra (utom page
och sort
).............................................................................................. Så vi kan fortsätta att skicka alla filter vi har ställt in i webbadressen till servern utan att behöva oroa sig för att de går förlorade när vi gör en ny begäran.
En av de snygga sakerna med HTMX är att mycket av dess interaktion med servern sker via HTTP-huvuden. Dessa rubriker ger servern ett rikt sammanhang om vad som utlöste begäran, så att du kan svara på lämpligt sätt från dina ASP.NET Core-slutpunkter eller Razor-vyer.
Återigen en viktig del av detta är HTMX.Net....................................... Bland många av de objekt den ger är prydliga Request
tillägg för att upptäcka HTMX-förfrågningar. Detta är användbart för att avgöra om en begäran gjordes av HTMX eller inte, och för att hantera den därefter.
Den har också sin egen mekanism för att skicka utlösningsdon
Response.Htmx(h => {
h.WithTrigger("yes")
.WithTrigger("cool", timing: HtmxTriggerTiming.AfterSettle)
.WithTrigger("neat", new { valueForFrontEnd= 42, status= "Done!" }, timing: HtmxTriggerTiming.AfterSwap);
});
Tryck Urls etc... etc... Khalid gjorde ett bra jobb med att skapa en uppsättning tillägg för att göra det enkelt att arbeta med HTMX i ASP.NET Core.
Det är ett nyckelverktyg i min verktygslåda när du arbetar med HTMX och ASP.NET Core. Kolla!
Här är en uppdelning av de mest användbara rubriker HTMX skickar med varje begäran:
på huvud med beskrivning på plats |----------------------------|------------------------------------------------------------------------------------------------------------------| på HX-request. Alltid inställd på true för alla HTMX-initierade begäran. Perfekt för att upptäcka HTMX-samtal i middleware eller regulatorer. Om ja, se till att det inte finns några tecken på att det inte finns någon anledning att tro att det inte finns någon anledning att tro att det inte finns någon anledning till det. Iden om målelementet i DOM som svaret kommer att bytas in i. Om ja, se till att det inte finns några tecken på att det inte finns någon anledning att tro att det inte finns någon anledning att tro att det inte finns någon anledning till det. Id för det element som utlöste begäran (t.ex. en knapp). Om ja, se till att det inte finns några tecken på att det inte finns någon anledning att tro att det inte finns någon anledning att tro att det inte finns någon anledning till det. på HX-Trigger-Name på det utlösande elementets namn (användbart för formulär). Om ja, se till att det inte finns några tecken på att det inte finns någon anledning att tro att det inte finns någon anledning att tro att det inte finns någon anledning till det. på HX-Prompt. Innehåller användarinmatning från hx-prompt. Om ja, se till att det inte finns några tecken på att det inte finns någon anledning att tro att det inte finns någon anledning att tro att det inte finns någon anledning till det. på HX-current-URL på webbläsaren URL när begäran initierades. Användbar för loggning och sammanhang. Om ja, se till att det inte finns några tecken på att det inte finns någon anledning att tro att det inte finns någon anledning att tro att det inte finns någon anledning till det. på HX-Historia-Restore-Request på engelska Skickas som sant om begäran är en del av en historik restaurering efter navigering (t.ex., tillbaka knapp). Om ja, se till att det inte finns några tecken på att det inte finns någon anledning att tro att det inte finns någon anledning att tro att det inte finns någon anledning till det.
Jag använder dessa ganska mycket i mina ASP.NET Core-appar. Kombinerat med HTMX.Net sådana som Request.IsHtmx()
, Request.IsHtmxBoosted()
och Request.IsHtmxNonBoosted()
Du kan enkelt upptäcka HTMX-förfrågningar och svara därefter.
Till exempel, Jag har en riktigt enkel förlängning till begäran som låter mig upptäcka om en begäran riktar sig till min huvudsakliga #page-content
Div. Jag vet inte. Om det är då vet jag att jag borde skicka tillbaka en del.
OBS: Många inser inte att du kan ange en "fullständig sida" som en partiell, det bara hoppar över layouten.
if (Request.PageContentTarget())
{
Response.PushUrl(Request);
return PartialView("List", vm);
}
return View("List", vm);
public static class RequestExtensions
{
public static bool PageContentTarget(this HttpRequest request)
{
bool isPageContentTarget = request.Headers.TryGetValue("hx-target", out var pageContentHeader)
&& pageContentHeader == "page-content";
return isPageContentTarget;
}
}
Förutom att begära förlängningar, kan du också skapa svar förlängningar för att skicka händelser tillbaka till klienten. Detta är användbart för att utlösa kundsidan händelser.
Till exempel i min SweetAlert2 integration Jag aktiverar att stänga dialogrutan med en utlösare som är inställd från servern.
document.body.addEventListener('sweetalert:close', closeSweetAlertLoader);
Detta utlöses från servern som en HTMX utlösande händelse.
public static void CloseSweetAlert(this HttpResponse response)
{
response.Headers.Append("HX-Trigger" , JsonSerializer.Serialize(new
{
sweetalert = "close"
}));
}
Detta kommer att utlösa sweetalert:close
händelse på klientens sida, så att du kan stänga dialogrutan. Du kan också skicka data tillbaka till klienten med hjälp av HX-Trigger
Huvudet. Detta är användbart för att överföra data från servern till klienten utan att behöva ändra HTML- eller JavaScript-koden.
Som ni ser är det mycket lätt att lyssna på dessa händelser genom att bara lägga till en händelselyssnare till kroppen. Jag använder JSON främst som det alltid kodar korrekt.
Jag skrev om min rostat bröd metod tidigare här, men det är värt att nämna här också. För att helt enkelt göra det möjligt för servern att utlösa en rostat bröd anmälan på klientens sida. Jag satte avtryckaren i denna svarsförlängning.
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
}
}));
}
Jag tar mig sedan in på evenemangsklientens sida och ringer min showToast
Funktion.
import { showToast, showHTMXToast } from './toast';
window.showHTMXToast = showHTMXToast;
document.body.addEventListener("showToast", showHTMXToast);
Detta kallar sedan in min showToast
funktion och väl, visar en skål; igen se mer om det i artikeln .
export function showHTMXToast(event) {
const xhr = event?.detail?.xhr;
let type = 'success';
let message = xhr?.responseText || 'Done!';
try {
const data = xhr ? JSON.parse(xhr.responseText) : event.detail;
if (data.toast) message = data.toast;
if ('issuccess' in data) {
type = data.issuccess === false ? 'error' : 'success';
} else if (xhr?.status >= 400) {
type = 'error';
} else if (xhr?.status >= 300) {
type = 'warning';
}
} catch {
if (xhr?.status >= 400) type = 'error';
else if (xhr?.status >= 300) type = 'warning';
}
showToast(message, 3000, type);
}
Det var allt, en virvelvindsturné av HTMX och ASP.NET Core. Jag hoppas att du fann det användbart och informativt. Om du har några frågor eller kommentarer är du välkommen att kommentera nedan.