# En vissel Tour över HTMX-extensioner och hur man använder HT MX med ASP.NET Core

<datetime class="hidden">2025-05-02T20:30</datetime>

<!--category-- Javascript, HTMX, ASP.NET Core -->
# Inleiding

HTMX är en kraftfull JavaScript bibliotek som tillåter dig att skapa dynamiska webbapplikationer med minimalt JavaScript.

Men jag säger fortfarande inte att jag har expertkunskaper om det. Jag ville bara dela med mig av några saker som jag lärt mig på vägen.

> **Kompanionsartikel:** Den här artikeln fokuserar på HTMX's händelsesystem , utvecklingar , och avancerad personalisering M SK3 För ASP.NET Korallintegrationsmönster med partiell syn på systemet [HTMX med ASP](/blog/htmx-aspnetcore-partials).

[TOC]

# Erfarelser

## Förberedels för begäran

Inställningsfasen är den där HTMX konfigurerar inställningen innan den skickas till servern.

```mermaid
flowchart LR

        A[htmx:configRequest] --> B[htmx:confirm] --> C[htmx:prompt] --> D[htmx:abort]

```

## begäran om livscykel

Den efterfrågans livscykelfasen är där HTMX skickar in begäran till servern och hanterar svaret. De följande händelserna aktiveras under den här fasen:

```mermaid
flowchart LR
 E[htmx:beforeRequest] --> F[htmx:request] --> G[htmx:afterRequest]
```

## Reaktionshantering

Response handlingsfasen är när HTMX bearbetar svaret från servern och uppdaterar dom.

```mermaid
flowchart LR
        H[htmx:beforeOnLoad] --> I[htmx:onLoad]
        I --> J[htmx:beforeSwap] --> K[htmx:swap] --> L[htmx:afterSwap]
        L --> M[htmx:afterSettle] --> N[htmx:afterOnLoad]

```

## Historiska avdelningar

Historiens hanteringsfas är när HTMX uppdaterar webbläsarens historia och URL. De följande händelserna aktiveras under den här fasen:

```mermaid
flowchart LR
 A[htmx:historyRestoreRequest]
 A --> B[htmx:historyPopped]
 B --> C[htmx:historyRestorePage]
```

Som ni kan se så erbjuder HTMX ett antal händelser som du kan koppla in för att modifiera begäran eller svaret.,, eller till och med historien.;. HT MX gör ett LITT för att vara ett så kompaktt system.

# Omlängningar

En av de kraftfullaste aspekterna av HTMX är förmågan att [skapa förlängningar](https://v2-0v2-0.htmx.org/extensions/) att utöka dess kapaciteter. I mitt fall `htmx:configRequest` att lägga till ytterligare parametrar till applikationen. Det är användbart när du vill skicka ytterligare data till servern utan att behöva modifiera HTML eller JavaScript-koden

Andra förlängningar kan hänga `htmx:beforeRequest` att ändra begäran innan den skickas **efter** de flesta andra förlängningar som hamnar `configRequest`; som i `beforeRequest` saker som `HX-Vals` och `HX-Include`s är redan kopplade till den vanligaste ( antingen i payloaden \ querystring
Du kan till och med ha `htmx:afterSwap` att utföra saker efter att innehållet har bytts ut. Kombinerat med klientseitiga templeringsbibliotek som [Alpine.js](https://alpinejs.dev/) eller [Lit](https://lit.dev/) du kan skapa kraftfulla dynamiska applikationer med minimal kod.

HTMX erbjuder några inbyggda extensioner som `hx-boost` och `hx-swap-oob` som tillåter dig att förbättra HTMXs funktionalitet utan att skriva någon egen kod.. Men det finns tillfällen då du behöver skapa dina egna förlängningar för att möta specifika krav.

Till exempel, kan du kanske vilja lägga till custom-Header till dina begäran , modifiera begäran-payloaden , eller hantera specifika händelser på ett unikt sätt

För att uppnå detta erbjuder HTMX några praktiska integreringspunkter:

```javascript

{
  /**
   * 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 erbjuder ett antal pre- byggda förlängningar som du kan [läsa om här](https://htmx.org/extensions/).

Till exempel en praktisk [byggt-in uitbreiding](https://github.com/bigskysoftware/htmx-extensions/blob/main/src/json-enc/README.md) `json-encode` möjliggör att skicka JSON-data i begäranbasen istället för URL-koderade formdata. Det är användbart när du vill skicka komplexa datastrukturer eller rutnät till servernM SK2
Ni kan se att detta kopplas till 3 händelser.

- `init` - för att sätta upp Erweiterungen och lagra en referens till HTMX API
- `onEvent` - för att sätta `Content-Type` header till `application/json` när begäran konfigureras
- `encodeParameters` - för att överrida den standardbaserade URL-koderade formkodering och serialisera parametrerna som JSONM SK2 Den återvänder också en ström för att förhindra HTMX från att använda den standardgjorda URL -koderad formkodingMSC4

```javascript
(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 den enklare men ännu mer praktiska `hx-debug` sträckning som lägger till en `HX-Debug` header till begäran. Det är användbart för avbugs- och loginsändningar, eftersom det tillåter dig att se råda begäran och reaktionsdata i devkonsolet

```javascript
(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 än "'", med en väldigt kraftfull [client side templating extension](https://github.com/bigskysoftware/htmx-extensions/tree/main/src/client-side-templates) som låter dig använda klient bibliotek för att omvandla JSON data till HTML. Detta är användbart för att skapa dynamiska gränssnitt utan att behöva lita på servern.

# Några anpassade förlängningar

## Dynamiska Ry IDs

Till exempel i ett nytt projekt använde jag HTMX OOB-svap för att uppdatera ett antal rader i en tabell.
För att göra detta ville jag veta vilka rader som nu visas i tabellen, så jag uppdaterade bara raderna som var synliga.

### Extensionen

```javascript
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
    }
}
```

### Att använda den

För att använda den behöver vi lägga till den till vår HTMX konfiguration.
Så i din ingångspunkt js-lêer ( antagligen att du ' använder moduler; det borde vara

```javascript
import dynamicRowIds from "./dynamicRowIds"; // Load the file

htmx.defineExtension("dynamic-rowids", dynamicRowIds); // Register the extension
```

På vilket element du än vill använda den kan du lägga till `hx-ext` attribut med värdet `dynamic-rowids`.

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

```

## Bevara parametrar

Det här är en annan enkel HTMX-extension `htmx:configRequest` som vi' modifierar URL: n innan rörelsen skickas. Den här utlängningen är tillförlitlig om du använder querystring-baserat filtering, etc.

Detta är SIMILAR till men inte exakt samma som den existerande HTMX-extensionen [push-params](https://github.com/bigskysoftware/htmx-extensions/blob/main/src/path-params/README.md)

### Extensionen

Ni kan se att vi `onEvent` att lyssna på `htmx:configRequest` händelse.

Så vi:

- få elementet som utlöste händelsen
- Ta den `preserve-params-exclude` attribut från elementet ( om det existerar) och delar det i en rad punkter för att utesluta ( så vi inte adderar dem till begäran
- få den nuvarande URL-parameterna från vensterlokalen
- få de nya parametrerna från formuläret
- Loopa genom den nuvarande parametern och kolla om de inte är i den uteslutande listan och inte redan i de nya parametrerna
- Om de inte är, så lägger vi dem till de nya parametrerna
- Slutligen, satte vi de nya parametrerna till rörelsens URL och gav tillbaka true för att fortsätta med rörelsen

```javascript
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 [HTMX.Net](https://github.com/khalidabuhakmeh/Htmx.Net/tree/main) för dess tag hjälpprogram. De liknande `hx-controller` och `hx-action` är tagbekymmer som genererar rätta HTMX-Attribute för dig. såväl som `hx-route-<x>` för värden att passera i vägen. Det är väldigt användbart eftersom det låter dig använda C# kod för att generera korrekta värden för attributen istället för att behöva hårdkoda dem i HTML

### Att använda den

Eftersom det är en förlängning så är det väldigt enkelt att använda

Först måste vi lägga till den till vår HTMX konfiguration.

```javascript

import preserveParams from './preserveParams.js';
htmx.defineExtension('preserve-params', preserveParams);
```

lägg märke till att standard HTMX-extensioner använder metoden 'autoload' för att ladda extensionen

```javascript
// Autoloading the extension and registering it
(function() {
  htmx.defineExtension('debug', {
}
```

Det är ett bra sätt att göra det om du använder HTMX i en icke-modulmiljö. `import` uttalande för att ladda utlängningen och sedan uttryckligen registrera den mot din `htmx` instance. Det här tillåter dig att dra nytta av trädet -shaking och bara ladda de utlängningar du behöver

Sedan kan du lägga till elementet `hx-ext` attribut med värdet `preserve-params` och `preserve-params-exclude` attribut med en komma-separerad lista av parametrer som ska uteslutas från begäran.

```html

<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 det här fallet `event.detail.path` att ha den nya `myparam` värde sätter den i den ' kommer ersätta den där med vår nya värde men bevara alla andra ( förutom `page` och `sort`). Så vi kan fortsätta skicka alla filter som vi har satt in i URL till servern utan att behöva oroa oss för att de förloras när vi gör en ny begäran

# ASP.NET Core

En av de häftiga sakerna med HTMX är att stor del av dess interaktion med servern sker genom HTTP-header. Dessa header ger servern en rik kontext om vad som upplöste begäran , och låter dig svara på det lämpligt från din ASP

Återigen en nyckelkomponent av detta är [HTMX.Net](https://github.com/khalidabuhakmeh/Htmx.Net/tree/main). Bland många av sakerna som den erbjuder är prydliga `Request` utlängningar för att upptäcka HTMX- begäran. Det är användbart för att avgöra om en begäran gjordes av HT MX eller inte , och för att hantera den på det sättet

Det har också sin egen mekanisme för att skicka utlösande signaler

```csharp

Response.Htmx(h => {
    h.WithTrigger("yes")
     .WithTrigger("cool", timing: HtmxTriggerTiming.AfterSettle)
     .WithTrigger("neat", new { valueForFrontEnd= 42, status= "Done!" }, timing: HtmxTriggerTiming.AfterSwap);
});
```

Push Urls etc...etc...
Khalid gjorde ett fantastiskt jobb med att skapa en uppsättning Erweiterunger för att göra det enkelt att jobba med HTMX i ASP

Det är ett nyckelverktyg i min verktygslåda när jag arbetar med HTMX och ASP [**Kolla ut det!**](https://github.com/khalidabuhakmeh/Htmx.Net/tree/main)

## Den vanliga HTMX-ansökande opskrifte

Här är en ventilation av de viktigaste opskriften som HTMX skickar med varje begäran.

| Header | Description |
|----------------------------|------------------------------------------------------------------------------------------------------------------|
| HX
| HX
| HX
| HX
| HX
| HX
| HX

## Tillåta Erweiterunger

Jag använder dessa ganska mycket i mina ASP-apps `Request.IsHtmx()` , `Request.IsHtmxBoosted()` och `Request.IsHtmxNonBoosted()` du kan enkelt upptäcka HTMX-behov och svara accordingly.

Till exempel, Jag har en väldigt enkel Erweiterung till Beställning som låter mig upptäcka om en begäran är riktad mot mitt huvud `#page-content` div. Om det är så vet jag att jag borde skicka tillbaka en del
NOTA: Många inser inte att man kan definiera en 'full sida ' som en del

```csharp
        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;
    }
    }

```

## Reaktionslängder

Förutom förlängningar till begäran, kan du också skapa förlängelser till respons för att skicka händelser tillbaka till klienten.

### Ett exempel på SweetAlert

Till exempel [i min SweetAlert2 integration](https://www.mostlylucid.net/blog/usingsweetalertforhxindicators) Jag gör det möjligt att stänga dialogen med hjälp av en aktivator som ställs från servern.

```javascript
    document.body.addEventListener('sweetalert:close', closeSweetAlertLoader);

```

Detta aktiveras från servern som en HTMX-utlösande händelse.

```csharp

    public static void CloseSweetAlert(this HttpResponse response)
    {
        response.Headers.Append("HX-Trigger" , JsonSerializer.Serialize(new
        {
            sweetalert = "close"
        }));

    }
```

Det här kommer att aktivera `sweetalert:close` händelse på klientsidan, som tillåter dig att stänga dialogen. Du kan också skicka tillbaka data till klienten med hjälp av `HX-Trigger` header. Det här är användbart för att skicka data från servern till klienten utan att behöva modifiera HTML eller JavaScript kod

Som ni ser, är det väldigt lätt att lyssna på dessa händelser genom att bara lägga till en händelse lyssnare i kroppen.

### ShowToast

Jag skrev tidigare om min toastmetod [här](https://www.mostlylucid.net/blog/showingtoastandswappingwithhtmx), men det är det som är värt att nämna här också . För att mycket enkelt kunna få servern att signalera en toast notification på klientens sida, ställde jag ut aktiveringen i den här reaktionsextensionen

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

    }
```

Sedan kopplar jag in mig i eventclientsidan och ringer till min `showToast` funktion.

```javascript
import { showToast, showHTMXToast } from './toast';

window.showHTMXToast = showHTMXToast;

document.body.addEventListener("showToast", showHTMXToast);
```

Det här låter mig `showToast` funktion och vält , visar en toast; se mer om det igen [i artikeln ](https://www.mostlylucid.net/blog/showingtoastandswappingwithhtmx).

```javascript


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

## I slutsats

Ja, det är det.

## Related Articles on This Blog

### Kompanionsartikel

Detta artikel är en del av en serie med två delar på HTMX med ASP

1. **[HTMX med ASP.NET Corepartial](/blog/htmx-aspnetcore-partials)** - fokuserar på ASP. Net Core integrering , partiell syn på , HTMX
2. **Denna artikel** - djupt dyka in i HTMX-eventen , livscykeln , utbyggnadsarkitekturen

### Fler HTMX-artiklar

- [Att lägga till webbningar med HTMX](/blog/addpagingwithhtmx) - Implementering av pagination med HTMX
- [ASP.Net Core Caching med HTMX](/blog/aspnetcachingwithhtmx) - Cachingsstrategier för HTMX-behov
- [Auto-refresh med Alpine och HTMX](/blog/autorefreshwithalpineandhtmx) - kombinerar Alpine.js med HTMX för reaktiva komponenter
- [Att göra din sida mer SPA-liknande med HTMX](/blog/htmxtomakeyoursitemorespalike) - SPA-liknande navigation utan JavaScript ramverk
- [Att använda SweetAlert för HX indikatorer](/blog/usingsweetalertforhxindicators) - vackra ladeindikatorer med HTMX
- [Att visa bröd och bytes med HTMX](/blog/showingtoastandswappingwithhtmx) - Server

## Fortsättning avläsning

**Officiell HTMX Dokumentation:**

- [HTMX Dokumentation](https://htmx.org/docs/) - Den officiella HTMX-dokumentationen
- [HTMX Eventreferens](https://htmx.org/events/) - Hela listan av HTMX händelser
- [HTMX-extensioner](https://htmx.org/extensions/) - De officiella HTMX-extensionerna
- [HTMX exempel](https://htmx.org/examples/) - Praktiska exempel på HTMX-mönster
- [HTMX Essays](https://htmx.org/essays/) - Tankfulla artiklar om HTMX-filosofi

**Bibliotek & verktyg:**

- [HTMX.NET GitHub](https://github.com/khalidabuhakmeh/Htmx.Net) - Bibliotekets källkod
- [HTMX.NET NuGet](https://www.nuget.org/packages/Htmx/) - HTMX.NET på NuGet
- [Khalid Abuhakmehs hemsida](https://khalidabuhakmeh.com/) - skapar HTMX
- [Alpine.js Dokumentation](https://alpinejs.dev/) - officiella Alpine-docks

**Samhällens resurser:**

- [HTMX-diskord](https://htmx.org/discord) - Aktivt samhällsstöd
- [Hypermediasystembok](https://hypermedia.systems/) - Gratis online bok om att bygga hypermediaapplikationer