Back to "Whistle-stop Tour of HTMX Extensions and Using HT MX with ASP.NET Core"

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

ASP.NET Core HTMX Javascript

Whistle-stop Tour of HTMX Extensions and Using HT MX with ASP.NET Core

Friday, 02 May 2025

Esitys

HTMX on tehokas JavaScript-libraari, joka antaa mahdollisuuden luoda dynaamisia web- sovelluksia vähimmäisJavaScriptin avulla.

En kuitenkaan vieläkään väitä, että minulla olisi asiasta asiantuntemusta. Halusin vain kertoa teille joitakin niistä asioista, jotka olen oppinut tällä tiellä.

Yhteinen artikla: Tässä artiklassa keskitytään HTMX-':n tapahtumajärjestelmään, ,:n laajennusten ja pitkälle kehitettyjen räätälöintien käyttöön..:n käyttö ASP:ssa sekä .:ssä ja NETissä. HTMX ASP:n kanssa.

Tapahtumat

Pyynnön valmistelu

Pyynnön valmisteluvaihe on se, jossa HTMX varmistaa pyynnön ennen kuin se lähetetään serverille.. Tähän sisältyy headerien asettaminen.

flowchart LR

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

Pyyntö elinkaari

Pyynnön elinkaaren vaiheessa HTMX lähettää pyynnön serverille ja käsittelee vastausta. Tämän vaiheen aikana käy ilmi seuraavat tapahtumat

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

Vastauksen käsittely

Vastauksen käsittelyvaihe on, kun HTMX käsittelee vastausta palvelimelta ja päivittää DOMin.

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]

Historian hallinta

Historianhallintavaihe on HTMX:n ajantasaistaminen hakukoneen historiasta ja URL:stä. Tämän vaiheen aikana käynnistetään seuraavat tapahtumat

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

Kuten näette, HTMX tarjoaa joukon tapahtumia, joihin voi liittyä pyynnön tai vastauksen muuttamiseksi.

Laajennus

Yksi tehokkaimmista HTMX:n näkökohdista on kyky laajentaminen laajentaa toimintavalmiuksiaan. Omassa tapauksessani htmx:configRequest lisätä lisäparametereja pyyntöön. Tämä on hyödyllistä, kun haluatte siirtää lisätietoja palveluun muuttamatta HTML:n tai JavaScriptin koodia

Muut laajennukset saattavat liittyä yhteen htmx:beforeRequest muuttamaan pyyntöä ennen kuin se lähetetään;, mutta sen jälkeen useimmat muut lisäykset, jotka kiinnittävät configRequest; sellaisena kuin beforeRequest asiat, kuten HX-Vals ja HX-Includes on jo liitetty toissijaiseen ( joko maksutaakkaan \ kysymyksenpyynnön stringiin Voitte jopa kiinnittää htmx:afterSwap toimien toteuttamiseen sen jälkeen, kun sisältö on vaihdettu. Yhdennetty client side templating librariesin kuten Alpine.js tai Liitti voitte luoda tehokkaita dynaamisia sovelluksia vähimmäiskoodin kanssa.

HTMX tarjoaa joitakin rakenteellisia -in lisäyksiä, kuten hx-boost ja hx-swap-oob jotka mahdollistavat HTMX:n toiminnallisuuden parantamisen kirjoittamatta mitään räätälöityä koodia. On kuitenkin tapauksia, joissa on tarpeen luoda omat lisäykset erityistarpeiden täyttämiseksi

Esimerkiksi, saatatte haluta lisätä pyyntöihinne räätälöityjä otsikoita, muuttaa pyynnön maksutaakkaaM SK2 tai käsitellä erityisiä tapahtumia ainutlaatuisella tavalla

Tämän saavuttamiseksi HTMX tarjoaa joustavat integrointipisteet:


{
  /**
   * 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 tarjoaa useita entiseen - -järjestelmään tehtyjä lisäyksiä, joita voi lukekaa siitä täällä.

Esimerkiksi hyödyllinen built-in laajentaminen json-encode sallii JSON-tietojen lähettämisen pyynnön kohdassa URL:n sijasta-encodoitujen lomakkeiden tietojen sijaan . Tämä on hyödyllistä, kun haluatte lähettää monimutkaisia tietorakenteita tai taulukoita palveluun Voitte nähdä, että tämä liittyy 3 tapahtumiin

  • init - laajentaminen ja viittauksen säilyttäminen HTMX-API:hen
  • onEvent - asettaa Content-Type header to application/json kun pyyntöä konfiguroidaan
  • encodeParameters - ei-todellisen URL:n ylipäätökseen ottamisesta -kodoidun lomakkeen kodifioimisesta ja parametrien serialisoimisesta JSONinaM SK2 Se myös palauttaa stringin, jolla estetään HTMX käyttämästä default-URL:tä-kodoitua lomakettaMSC4
(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))
    }
  })
})()

Tai jopa yksinkertaisempi, mutta vieläkin käsittävämpi hx-debug lisäys, joka lisää HX-Debug pyynnön otsikko. Tämä on hyödyllinen parannuskeinojen ja logging-tarkoituksiin,, koska se antaa mahdollisuuden nähdä raakapyynnön ja vastauksen tiedot dev-konsolissa

(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')
      }
    }
  })
})()

':ta on paljon enemmän, myös erittäin tehokas Client side templating extension , jonka avulla voidaan käyttää client-välistä templointia käyttäviä kirjastoja muuntamaan palautetut JSON-tiedot HTML:iin. Tämä on hyödyllistä dynaamisten UI:ien luomiseksi ilman, että tarvitsee turvautua serveriin -välin renderoimiseen

Jotkin räätälöityt lisäykset

Dynaamiset Row ID:t

Esimerkiksi äskettäisessä hankkeessa käytin HTMX OOB-vaihtoehtoja, jotta ajantasaistetaan useita riviä taulukossa. Tätä varten halusin tietää, mitkä rivit esitetään tällä hetkellä taulukossa.

Laajentaminen

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

Käyttämällä sitä

Jotta sitä voitaisiin käyttää, meidän on lisättävä HTMX-configurationimme lisäys. Siten omassa lähtökohdassanne js-tiedostossa ( olettaen, että olette käyttämässä mallejaM SK2 teidän pitäisi olla ) voitte tehdä jotain tämänkaltaista

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

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

Sitten mihin tahansa elementtiin, jota haluatte käyttää, voitte lisätä hx-ext ominaisuuksia, joiden arvo on 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>

Varmistakaa kohdat

Tämä on toinen yksinkertainen HTMX-lisäys,, joka on tällä kertaa sidottu htmx:configRequest , kun muutamme URL:tä ennen pyynnön lähettämistä. Tämä laajentaminen on hyödyllistä, jos haluatte, että jotkin pyynnöt säilyttävät olemassa olevat filtrit ja toiset eivät

Tämä on samanlainen mutta ei täysin sama kuin nykyinen HTMX-laajennus push-params

Laajentaminen

Kuten voitte nähdä, onEvent kuunnella htmx:configRequest tapahtuma.

Sitten me:

  • Otetaan elementti, joka käynnisti tapahtuman
  • Ottakaa preserve-params-exclude , jos se on olemassa) ja jakaa sen avainkokonaisuudeksi poistaakseen (, joten emme lisää niitä pyyntöön
  • Ottakaa nykyiset URL-parameterit ikkunan sijaintipaikasta
  • Ottakaa uudet parametrit pyynnön URL:stä
  • Läpäisy nykyisten parametrien läpi ja tarkistaa, eivätkö ne ole poissuljettu luettelossa eivätkä jo uudet parametrit
  • Jos ne eivät ole,, lisäämme ne uusiin parametreihin
  • Lopuksi, asetamme uudet parametrit pyynnön URL:hen ja palautamme totuuden jatkaaksemme pyyntöä.
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;
    }
};

Käytän tässä olennaista HTMX.Net its tag helpers. hx-controller ja hx-action ovat merkintähelporeita, jotka tuottavat teille oikeat HTMX-ominaisuudet. sekä hx-route-<x> on todella hyödyllistä, koska se antaa mahdollisuuden käyttää C-koodia todellisten arvojen luomiseksi ominaisuuksille sen sijaan, että niitä olisi kodifioitava HTML:ssänne.

Käyttämällä sitä

Koska se on laajennus, sitä on todella helppo käyttää

Ensinnäkin meidän on lisättävä HTMX-configurationimme laajennus.


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

PANEE MERKILLE: Teidän on huomautettava, että HTMX:n tavanomaiset laajennusmenetelmät käyttävät 'autoloadM SK3 menetelmää ladatakseen laadinnon.

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

Tämä on hyvä tapa tehdä se, jos olette käyttämässä HTMX:tä muussa kuin - -muunnelmaympäristössä. import julistus ladata laajennus ja sitten nimenomaisesti rekisteröidä se vastauksena htmx instance. Tämä mahdollistaa sen, että hyödynnätte puun rakennetta -shakingia ja laaditte vain tarvitsemanne laajennusten

Sitten elementtin voin lisätä hx-ext ominaisuuksia, joiden arvo on preserve-params ja preserve-params-exclude periaate, johon sisältyy selitetty luettelo parametreista, joita pyynnöstä on poistettava.


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

Tässä tapauksessa event.detail.path uusi myparam arvo asettaa sen siihen' korvaa tämän uuden arvomme, mutta säilyttää kaikki muut M SK1 lukuun ottamatta page ja sort). Voimme siis siirtää kaikki URL-osoitteessa määritellyt filtrit edelleen palveluun ilman, että meidän on huolehdittava niiden katoamisesta, kun teemme uuden pyynnön.

ASP.NET Core

HTMX:n eräs hieno asia on se, että suuri osa sen vuorovaikutuksesta serveriin tapahtuu HTTP-otsikkojen välityksellä. Nämä otsikot antavat serverille rikkaan kontekstin siitä, mikä teki pyynnön lähtökohdaksi.

Jälleen kerran tämän keskeinen osatekijä on HTMX.Net. Monista sen tarjoamista tuotteista monet ovat huolellisia Request HTMX-pyyntöjen havaitsemiseen tarkoitettuja lisäyksiä. Tämä on hyödyllinen, jotta voidaan määritellä, tekikö HT MX pyynnön vai ei, ja käsitellä sitä vastaavasti

Sillä on myös oma mekanismi,


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

Push Urls jne...etc... Khalid teki loistavan työn laatiessaan joukon lisäyksiä, jotka helpottavat HTMXin käyttöä ASP:ssa

HTMX:n ja ASP:n kanssa työskennellessäni se on keskeinen väline. Katsokaa se!

Yleiset HTMX-pyynnön otsikot

Tässä on HTMX:n lähettämien hyödyllisimpien otsikoiden jakautuminen jokaiseen pyyntöön.

Luettelo
HX
HXM SK1Target DOM:n kohdeelementin ID, johon vastaus korvataan
HX
HX
HX
HX
HX -Historia-RestoreM SK3Täkymys SSK4 Lähetetään totuudenmukaisesti, jos pyyntö on osa historian palauttamista navigoinnin jälkeen.

Pyydän lisäyksiä

Käytän näitä melko laajasti ASP:ssani Request.IsHtmx() , Request.IsHtmxBoosted() ja Request.IsHtmxNonBoosted() voitte helposti havaita HTMX-pyynnöt ja vastata niihin..

Esimerkiksi, Minulla on todella yksinkertainen lisäys pyyntöön, joka antaa minulle mahdollisuuden havaita, kohdennetaanko pyyntö maininiin. #page-content div. Jos se on, niin tiedän, että minun pitäisi lähettää takaisin osittainen PANEE MERKILLE: Monet eivät realize you can specify a 'full pageM SK3 as a partial , it then just skips the layout

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

Vastauksen laajentaminen

Pyyntöjen laajennusten lisäksi, voitte myös luoda vastauksen laajennettuja toimenpiteitä tapahtumien lähettämiseksi takaisin klientilleM SK1 Tämä on hyödyllistä Client-puolisten tapahtumista aktivoimiseksi.

SweetAlert -esimerkki

Esimerkiksi SweetAlert2 integroinnissani Saanen lopettaa vuoropuhelun käyttämällä lähtölaukauksen, joka on asetettu palvelijalta.

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

Tämä aktivoidaan palvelimelta HTMX:n aktivointitapahtumana.


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

    }

Tämä käynnistää sweetalert:close tilanteesta riippuvainen tapahtuma,, joka mahdollistaa vuoropuhelun sulkemisen HX-Trigger header. Tämä on hyödyllinen tietojen välittämiseksi palvelimelta Clientiin muuttamatta HTML- tai JavaScript-koodia

Kuten näette' on täysin helppo kuunnella näitä tapahtumia vain lisäämällä tapahtumien kuuntelijan kehoonM SK1 Käytän JSONia pääasiassa siksi, että se sekoittaa aina asianmukaisesti

ShowToast

Olen kirjoittanut aiemmin savutusmenetelmästäni täällä, mutta se ' kannattaa mainita myös täälläM SK2 Voidakseni hyvin yksinkertaisesti aktivoida serverin toast-ilmoituksen Client-puolelle. Asetsin aktivaattorin tähän vastauksen laajennuseen

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

    }

Siirryn sitten tapahtuman asiakkaiden puoleen ja kutsun showToast Funktio.

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

window.showHTMXToast = showHTMXToast;

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

Tämä kutsuu sitten minuun showToast function and well, osoittaa toastM SK1 jälleen nähdä enemmän siitä artiklassa .



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

Päätelmissä

No niin, että's se,hirlwind Tour of HTMX and ASP .NET CoreM SK3 Toivon, että olette löytäneet sen hyödylliseksi ja informativeksiMSC4 Jos teillä on kysymyksiä tai huomautuksia, voitte ystävällisesti kommentoida sitä jäljempänä.

Yhteinen artikla

Tämä artikla on osa HTMX:n kahta osasarjaa ASP:n kanssa

  1. HTMX ASP.NETin ydinosapuolten kanssa - keskittyy ASP:iinM SK1NETin ydinintegraatioon , osittaisiin näkemyksiin M SK3 HTMX.NETMSC5 ja sivuuttamiseen
  2. Tämä artikkeli - HTMX-tapahtumiin syvällinen virtaaminen , elinkaari

Lisätietoja HTMX-artikkeleista

Lisä lukeminen

Virallinen HTMX-asiakirja:

Luettelo kirjastoista & välineet:

Yhteisön resurssit:

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.