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.  
Wednesday, 23 April 2025
//7 minute read
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 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:
Nel mio progetto uso già
Quindi la mia soluzione era focalizzata sull'utilizzo di questi per ottenere una bella soluzione funzionale con un codice minimo.
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>");
    }
}
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.
target attributoHai 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";
Questi risultano nel rendering del seguente HTML:
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>
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>
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...
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;
showAlert funzione utilizzando SweetAlert2Si 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.
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
            });
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.