Back to "En alpin.js och HTMX aktiverade tagghjälp för 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

Alpine.js ASP.NET Core HTMX Javascript

En alpin.js och HTMX aktiverade tagghjälp för ASP.NET Core

Wednesday, 23 April 2025

Inledning

Bara en snabb en, Jag hade ett behov i ett arbete projekt för förmågan att "clear" URL parametrar från en URL. Detta är användbart när du har en URL med flera parametrar, och du vill ta bort en eller flera av dem (till exempel för ett sökfilter).

Problemet

Mitt nuvarande projekt använder gamla skolan frågesträngar (det är en admin webbplats så behöver inte fantasin i "nice" webbadresser). Så jag slutar med en URL som denna:

/products?category=electronics&search=wireless+headphones&sort=price_desc&inStock=true&page=3

Nu kan dessa variera med varje sida, så jag kan sluta med en BUNCH i sidan URL och jag måste kunna rensa dem utan att skriva ett gäng pannplattor för att göra det.

Du KAN göra detta som en del av vilken inmatningskontroll du än använder så till exempel bredvid varje kryssruta (eller en tjusig platshållare stil tydlig ikon) men och du kan använda denna teknik för dem också. Men i det här fallet ville jag göra två viktiga saker:

  1. Kunna rensa en namngiven parameter
  2. Kunna rensa en lista över parametrar.
  3. Kunna rensa alla parametrar
  4. Skicka tillbaka det med HTMX
  5. Låt den använda min laddningsindikator min laddningsindikator.

Lösningen

I mitt projekt använder jag redan

  • HTMX Ordförande
  • Alpina.js
  • ASP.NET Kärna
  • Släpfordon och påhängsvagnar
  • DaisyUI Ordförande

Så min lösning var fokuserad kring att använda dessa för att få en snygg, funktionell lösning med minimal kod.

Taggens hjälpare

Min TagHelper är ganska enkel, allt jag gör är att skapa en <a> Tagg med några attribut Jag kommer senare att passera in i Alpine Module och vi är klara.

[HtmlTargetElement("clear-param")]
public class ClearParamTagHelper : TagHelper
{
    [HtmlAttributeName("name")]
    public string Name { get; set; }
    
    [HtmlAttributeName("all")]
    public bool All { get; set; }= false;
    
    [HtmlAttributeName("target")]
    public string Target { get; set; } = "#page-content";

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "a";
        output.Attributes.SetAttribute("x-data", "window.queryParamClearer({})");

        if (All)
        {
        output.Attributes.SetAttribute("x-all", All);
        }
        else
        {
            output.Attributes.SetAttribute("x-param", Name);
        }
        output.Attributes.SetAttribute("data-target", Target);
        output.Attributes.SetAttribute("x-on:click.prevent", "clearParam($event)");
        output.Content.SetHtmlContent(@"
            <div class='w-6 h-6 flex items-center justify-center bg-red-600 text-white rounded-full'>
                <i class='bx bx-x text-lg'></i>
            </div>");
    }
}

För en driftspänning av mer än 1000 V men högst 1000 V

I bruk ser detta ut så här, först för "klarera alla parametrar". Så jag tittar bara på Context.Request.Query om det finns några parametrar där jag gör den lilla x ikonen för att låta användaren rensa alla parametrar.


@if(Context.Request.Query.Any())
{
<label class="param-label">
    <clear-param all="true"></clear-param>
    clear all
</label>
}
</div>

Alternativt för namngivna parametrar kan jag göra detta


<div class="param-label">
    <clear-param name="myParam"></clear-param>
    <p>My Param: @Model.MyParam</p>
</div>

Vilket naturligtvis skulle tydliggöra den enda parametern.

Eller till och med


<div class="param-label">
    <clear-param name="myParam1,myParam2,myParam3"></clear-param>
    <p>My Param: @Model.MyParam1</p>
    <p>My Param: @Model.MyParam2</p>
    <p>My Param: @Model.MyParam3</p>
</div>

Detta rensar sedan alla namngivna parametrar från strängen.

I detta sammanhang är det viktigt att se till att target egenskap

YOu har också möjlighet att passera i en target attribut som kommer att användas som hx-target Egenskap. Detta är användbart om du vill uppdatera en specifik del av sidan med det nya innehållet.


<div class="param-label">
    <clear-param name="myParam" target="#my-thing"></clear-param>
    <p>My Param: @Model.MyParam</p>
</div>

I mitt fall (eftersom jag skrev det) Jag försummade målet till min #page-content Div. Jag vet inte.

    [HtmlAttributeName("target")]
    public string Target { get; set; } = "#page-content";

Resultatet

Dessa resulterar i rendering av följande HTML:

  • Alla: Så vi får HTML med x-all attribut och nr x-param Egenskap.
<a x-data="window.queryParamClearer({})" x-all="True" data-target="#page-content" x-on:click.prevent="clearParam($event)">
    <div class="w-6 h-6 flex items-center justify-center bg-red-600 text-white rounded-full">
        <i class="bx bx-x text-lg"></i>
    </div>
</a>

  • Ensam Vi får HTML med x-param attribut och nr x-all Egenskap.
<a x-data="window.queryParamClearer({})" x-param="myParam" data-target="#page-content" x-on:click.prevent="clearParam($event)">
    <div class="w-6 h-6 flex items-center justify-center bg-red-600 text-white rounded-full">
        <i class="bx bx-x text-lg"></i>
    </div>
</a>
  • Flera Vi får HTML med x-param attribut med en kommaseparerad sträng och nr x-all Egenskap.
<a x-data="window.queryParamClearer({})" x-param="myParam1,myParam2,myParam3" data-target="#page-content" x-on:click.prevent="clearParam($event)">
    <div class="w-6 h-6 flex items-center justify-center bg-red-600 text-white rounded-full">
        <i class="bx bx-x text-lg"></i>
    </div>
</a>

Var och en av dem har också de två alpina attributen x-data och x-on:click.prevent som används för att ställa in Alpmodulen och kalla funktionen för att rensa parametrarna.

Vi får se hur det fungerar härnäst...

Den alpina modulen

Detta är naturligtvis möjligt genom användning av Alpine.js att konfigurera vår begäran och HTMX att utföra det.

Som du kan se i koden nedan, Jag har en enkel modul som tar path av den aktuella sidan och sedan använder URL API för att tolka frågesträngen (du kan också passera i en annan av någon anledning :)).

Vi får sedan elementet som klickades och kontrollera om det har x-all attribut; om det gör vi tar bort alla parametrar från webbadressen, annars vi dela x-param Attribuera med kommatecken och ta bort var och en av dessa parametrar.

Sedan skapar vi en ny URL med den uppdaterade frågesträngen och använder HTMX för att göra en begäran till den URL:en.

export function queryParamClearer({ path = window.location.pathname }) {
    return {
        clearParam(e) {
            const el = e.target.closest('[x-param],[x-all]');
            if (!el) return;

            const url = new URL(window.location.href);

            if (el.hasAttribute('x-all')) {
                // → delete every single param
                // we copy the keys first because deleting while iterating modifies the collection
                Array.from(url.searchParams.keys())
                    .forEach(key => url.searchParams.delete(key));
            } else {
                // → delete only the named params
                (el.getAttribute('x-param') || '')
                    .split(',')
                    .map(p => p.trim())
                    .filter(Boolean)
                    .forEach(key => url.searchParams.delete(key));
            }

            const qs = url.searchParams.toString();
            const newUrl = path + (qs ? `?${qs}` : '');

            showAlert(newUrl);
            htmx.ajax('GET', newUrl, {
                target: el.dataset.target || el.getAttribute('hx-target') || 'body',
                swap: 'innerHTML',
                pushUrl: true
            });
        }
    };
}

//In your entry point / anywhere you want to register the module
import { queryParamClearer } from './param-clearer.js'; // webpackInclude: true

window.queryParamClearer = queryParamClearer;

I detta sammanhang

logo

©2024 Scott Galloway