Un aiutante di tag abilitato Alpine.js e HTMX per ASP.NET Core (Italiano (Italian))

Un aiutante di tag abilitato Alpine.js e HTMX per ASP.NET Core

Comments

NOTE: Apart from English (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.

Wednesday, 23 April 2025

//

Less than a minute

Introduzione

Solo uno veloce, ho avuto una necessità in un progetto di lavoro per la capacità di 'pulire' parametri URL da un URL. Questo è utile quando si dispone di un URL con più parametri, e si desidera rimuovere uno o più di essi (per esempio per un filtro di ricerca).

Il problema

Il mio attuale progetto utilizza stringhe di query old-school (è un sito di amministrazione quindi non ha bisogno della fantasia di 'belle' urls). Quindi finisco con un URL come questo:

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

Ora questi possono variare ad ogni pagina, così posso finire con un BUNCH nell'URL della pagina e ho bisogno di essere in grado di cancellarli senza scrivere un mazzo di piastra caldaia per farlo.

Si può fare questo come parte di qualsiasi controllo di input si utilizza così, ad esempio, accanto a ogni casella di controllo (o uno stile di segnaposto di fantasia icona chiara) ma e si può utilizzare questa tecnica per quelli troppo. Tuttavia, in questo caso volevo fare due cose principali:

  1. Essere in grado di cancellare un parametro chiamato
  2. Essere in grado di cancellare una lista di parametri.
  3. Essere in grado di cancellare tutti i parametri
  4. Rimandalo indietro con HTMX
  5. Usa il mio indicatore di carico il mio indicatore di carico.

La soluzione

Nel mio progetto uso già

  • HTMX
  • Alpine.js
  • ASP.NET Core
  • CSS a vento di coda
  • DaisyUICity name (optional, probably does not need a translation)

Quindi la mia soluzione era focalizzata sull'utilizzo di questi per ottenere una bella soluzione funzionale con un codice minimo.

L'aiutante per il tag

Il mio TagHelper è abbastanza semplice, tutto quello che faccio è creare un <a> Tag con alcuni attributi Passerò più tardi nel Modulo Alpino e abbiamo finito.

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

Parametri

In uso questo sembra così, prima per 'chiarire tutti i parametri'. Quindi ho solo guardato il Context.Request.Query Se ci sono dei parametri li'... Rendero' il piccolo... x icona per consentire all'utente di cancellare tutti i parametri.


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

Alternativamente per i parametri nominati posso fare questo


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

Il che, ovviamente, chiarirebbe quel singolo parametro.

O addirittura...


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

Questo cancella quindi tutti i parametri nominati dalla stringa.

La target attributo

Hai anche la possibilità di passare in un target attributo che sarà utilizzato come hx-target attributo. Questo è utile se si desidera aggiornare una parte specifica della pagina con i nuovi contenuti.


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

Nel mio caso (perché l'ho scritto) ho predefinito l'obiettivo al mio #page-content Div.

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

Il risultato

Questi risultano nel rendering del seguente HTML:

  • Tutti: Quindi otteniamo HTML con il x-all attributo e no x-param attributo.
<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>

  • SingoloCity name (optional, probably does not need a translation) Otteniamo HTML con il x-param attributo e no x-all attributo.
<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>
  • Multiplo Otteniamo HTML con il x-param attributo con una stringa separata da virgola e no x-all attributo.
<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>

Ognuno di essi ha anche i due attributi alpini x-data e x-on:click.prevent che vengono utilizzati per impostare il modulo alpino e chiamare la funzione per cancellare i parametri.

Vedremo come funziona la prossima...

Il modulo alpino

Questo è ovviamente reso possibile dall'utilizzo di Alpine.js per configurare la nostra richiesta e di HTMX per eseguirla.

Come potete vedere nel codice qui sotto, ho un semplice modulo che prende il path della pagina corrente e poi utilizza la URL API per analizzare la stringa di query (si potrebbe anche passare in un diverso per qualsiasi motivo:)).

Poi otteniamo l'elemento che è stato cliccato e controllare se ha il x-all attributo; se lo fa cancelliamo tutti i parametri dall'URL, altrimenti dividiamo il x-param attributo per virgole ed eliminare ciascuno di questi parametri.

Poi creiamo un nuovo URL con la stringa di query aggiornata e usiamo HTMX per fare una richiesta a quell'URL.

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;

La showAlert funzione utilizzando SweetAlert2

Si noterà anche che io chiamo un showAlert funzione. Questo è solo un semplice involucro intorno all'indicatore di carico SweetAlert2 che uso nel mio progetto. Ovviamente puoi sostituirlo con qualsiasi cosa tu voglia fare."

Questo è leggermente modificato dal L'ultima volta che l'abbiamo visto.. Cosi' potevo estrarre il showAlert funzionare e metterlo a disposizione di moduli esterni. Che mi permette di usarlo in entrambi i param-clearer il modulo e il hx-indicator modulo.

export function registerSweetAlertHxIndicator() {
    document.body.addEventListener('htmx:configRequest', function (evt) {
        const trigger = evt.detail.elt;

        const indicatorAttrSource = getIndicatorSource(trigger);
        if (!indicatorAttrSource) return;

        // ✅ If this is a pageSize-triggered request, use our custom path
        let path;
        if (evt.detail.headers?.['HX-Trigger-Name'] === 'pageSize') {
            path = getPathWithPageSize(evt.detail);
            console.debug('[SweetAlert] Using custom path with updated pageSize:', path);
        } else {
            path = getRequestPath(evt.detail);
        }

        if (!path) return;
        evt.detail.indicator = null;
        showAlert(path);
    });
}

export function showAlert(path)
{
    const currentPath = sessionStorage.getItem(SWEETALERT_PATH_KEY);

    // Show SweetAlert only if the current request path differs from the previous one
    if (currentPath !== path) {
        closeSweetAlertLoader();
        sessionStorage.setItem(SWEETALERT_PATH_KEY, path);


        Swal.fire({
            title: 'Loading...',
            allowOutsideClick: false,
            allowEscapeKey: false,
            showConfirmButton: false,
            theme: 'dark',
            didOpen: () => {
                // Cancel immediately if restored from browser history
                if (sessionStorage.getItem(SWEETALERT_HISTORY_RESTORED_KEY) === 'true') {
                    sessionStorage.removeItem(SWEETALERT_HISTORY_RESTORED_KEY);
                    Swal.close();
                    return;
                }

                Swal.showLoading();
                document.dispatchEvent(new CustomEvent('sweetalert:opened'));

                // Set timeout to auto-close if something hangs
                clearTimeout(swalTimeoutHandle);
                swalTimeoutHandle = setTimeout(() => {
                    if (Swal.isVisible()) {
                        console.warn('SweetAlert loading modal closed after timeout.');
                        closeSweetAlertLoader();
                    }
                }, SWEETALERT_TIMEOUT_MS);
            },
            didClose: () => {
                document.dispatchEvent(new CustomEvent('sweetalert:closed'));
                sessionStorage.removeItem(SWEETALERT_PATH_KEY);
                clearTimeout(swalTimeoutHandle);
                swalTimeoutHandle = null;
            }
        });
    }
}

//Register it
import { registerSweetAlertHxIndicator, showAlert } from './hx-sweetalert-indicator.js';
registerSweetAlertHxIndicator();
window.showAlert = showAlert;

Come promemoria questo usa il path come chiave per sapere quando nascondere l'allarme.

HTMX

Infine, usiamo htmx.ajax per fare la richiesta. Questa è una semplice richiesta GET al nuovo URL che abbiamo creato con la stringa di query aggiornata.

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

In conclusione

Questo è un modo semplice per cancellare i parametri URL usando un tag helper e Alpine.js. Consente di cancellare tutti i parametri, o solo quelli specifici, con codice minimo.

logo

©2024 Scott Galloway