# Alpine.js ja HTMX 'Pääselvä hakujoukkoparameteri

<datetime class="hidden">2025-04-25T23:00</datetime>

<!--category-- Javascript, HTMX, Alpine.js, ASP.NET Core -->
# Esitys

Tämä on hyödyllistä, kun URL: ssa on useita parametreja, ja jos haluat poistaa yhden tai useamman niistä.

[TOC]

# Ongelma

Nykyisessä hankkeessani käytetään vanhoja-koulua koskevat kysymykseen liittyvät stringit (itM SK2 on hallinnollinen sivusto, joten ei' tarvita fanciness-läheyttä.

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

```

Nyt ne voivat vaihdella kussakin sivussa,, joten voin päätyä siihen, että sivun URL: ssä on BUNCH ja minun on pystyttävä poistamaan ne kirjoittamatta mitään boilerplatea sen tekemiseksi.

Voitte tehdä tämän osana riippumatta siitä, mitä input-valvontaa olette käyttämässä, joten esimerkiksi jokaisen tarkistuskäsitteen läheisyydessä ( tai fancy placeholder style clear icon) mutta ja voitte käyttää tätä tekniikkaa myös niille . Joka tapauksessaM SK3 tässä tapauksessa halusin tehdä kaksi pääasiallista asiaa

1. Voidaan poistaa nimetty parametri
2. Voidaan selvittää luettelo parametreista.
3. Voidaan selvittää kaikki parametrit
4. Onko se lähetetty takaisin HTMX:n kanssa
5. Onko se käyttänyt lastausindikaattoriani? [lastausindikaattorini](https://www.mostlylucid.net/blog/usingsweetalertforhxindicators).

# Ratkaisu

Omassa hankkeessani käytän jo

- HTMX
- Alpine.js
- ASP.NET Core
- TailwindCSS
- DaisyUI

Näin ollen ratkaisuni keskityi näiden käyttämiseen saadakseni mukavan lookallisen käytännöllisen ratkaisun vähimmäiskoodilla

## Tagin avustaja

Minun TagHelper on varsin yksinkertainen, kaikki, mitä teen, on luoda `<a>` merkintö, jossa on joitakin ominaispiirteitä I' siirtyy myöhemmin alppimuunttiin ja teemme sen

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

### Parametrit

Käytössä tämä näyttää olevan seuraavaa, ensin 'selvi kaikki parametritM SK2 joten katson vain `Context.Request.Query` jos siellä on '-parametereja, esitän pienet `x` icon, jonka avulla käyttäjä voi poistaa kaikki parametrit.

```html

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

```

Vaihtoehtoisesti nimettyjen parametrien osalta voin tehdä tämän

```html

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

Tämä selventäisi luonnollisesti sitä, että yksi ainoa parametri.

Tai jopa

```html

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

Tämän jälkeen kaikki nimetut parametrit selvitetään string.:sta.

### Euroopan unionin `target` luonne

Teillä on myös mahdollisuus päästä läpi `target` ominaisuuksia, joita käytetään `hx-target` attribute. Tämä on hyödyllinen, jos haluatte ajanmukaistaa tiettyä sivun osaa uudella sisällöllä.

```html

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

Omassa tapauksessani (, koska kirjoitin sen ). `#page-content` Div.

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

```

### Tulos

Näiden tulosten perusteella voidaan esittää seuraava HTML:

- Kaikki:
  Saamme siis HTML:n `x-all` ominaisuuksia ja ei `x-param` ominaisuuksia.

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

```

- Yksittäinen
  Saamme HTML:n `x-param` ominaisuuksia ja ei `x-all` ominaisuuksia.

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

- Useat
  Saamme HTML:n `x-param` ominaisuuksia, joilla on comma-separannettu string ja ei `x-all` ominaisuuksia.

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

Kaikilla niillä on myös kaksi alppimaisen ominaisuutta. `x-data` ja `x-on:click.prevent` , joita käytetään Alpine-muunnoksen perustamiseen ja kutsutaan toiminnaksi, jotta parametrit selvitetään.

Katsomme seuraavaksi, miten se toimii.

## Alppimuudelma

Tämä on tietenkin mahdollista Alpine.js:n avulla, jotta voimme konfiguroida pyynnön ja HTMX:n voida toteuttaa sen.

Kuten näette jäljempänä olevassa koodissa, minulla on yksinkertainen moduuli, joka `path` ja käyttää sen jälkeen `URL` API, jolla analysoidaan kysymyksen stringi ( voitte myös siirtää toisesta syystä

Saamme sitten elementin, joka oli klikattu ja tarkistaa, onko sillä `x-all` attribute; jos se poistaa kaikki parametrit URL:stä, muilta osin jaamme `x-param` ja poistaa kukin näistä parametreista.

Sen jälkeen luomme uuden URL:n, jossa on ajantasaistettu kysymyksen string ja käytämme HTMX:tä, jotta voimme esittää pyynnön kyseiselle URL:lle.

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

### Euroopan unionin `showAlert` SweetAlert-operaatio

Huomaatte myös, että minä kutsun `showAlert` function. Tämä on vain yksinkertainen wrapper SweetAlertin ympärille.

Tämä on hieman mukautettu [viime kerralla nähimme sen](https://www.mostlylucid.net/blog/usingsweetalertforhxindicators). Voisin siis extrahoida `showAlert` ja tehdä siitä saatavilla ulkoisia moduuleja., jotka antavat's minulle käyttää sitä molemmissa `param-clearer` Moduli ja `hx-indicator` moduuli.

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

Muistutuksena käytetään `path` avain, jonka avulla voidaan tietää, milloin varoittaa hälytys

### HTMX

Lopuksi käytämme `htmx.ajax` to make the request. Tämä on yksinkertainen GET-pyynnös uudelle URL:lle, jonka olemme luoneet ajantasaistetut kysymyksensa stringin kanssa

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

# Päätelmissä

Tämä on yksinkertainen tapa selviytyä URL-parametereista käyttämällä tag helperia ja Alpinea.