Увімкнені альпійські. js і HTMX помічник теґів для ядра ASP. NET (Українська (Ukrainian))

Увімкнені альпійські. js і HTMX помічник теґів для ядра ASP. NET

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

Вступ

Я мав потребу в робочому проекті, щоб визначити параметри адреси URL з адреси URL. Цей пункт буде корисним, якщо у вас є адреса URL з декількома параметрами, і ви бажаєте вилучити один або декілька з них (наприклад, для фільтра пошуку).

Проблема

У моєму поточному проекті використовуються рядки запитів зі старої школи (це адміністративний сайт, отже, йому не потрібна фантастика адрес 'nice'). Отже, у мене з'явився такий URL:

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

Тепер вони можуть змінюватися з кожною сторінкою, так що я можу отримати BUNCH в адресі page і я повинен мати можливість очистити їх, не написавши купу котел для цього.

Ви можете зробити це як частину керування вхідними даними, яку ви використовуєте, наприклад, поряд з кожною з позначок (або показною піктограмою у стилі заповнювача з чіткими піктограмами), але ви також можете скористатися цією технікою. Проте, у цьому випадку я хотів зробити дві головні речі:

  1. Можливість спорожнення іменованого параметра
  2. Можливість спорожнення списку параметрів.
  3. Можливість спорожнення всіх параметрів
  4. Поставити його назад з HTMX
  5. Нехай він використовує мій індикатор завантаження мій індикатор завантаження.

Розв'язання

В моєму проекті я вже використовую

  • HTMX
  • Альпійський.js
  • Ядро ASP. NET
  • Вихровий вітроплав
  • DaisUI

Моє рішення зосереджувалося на використанні цих засобів, щоб отримати гарне, функціональне рішення з мінімальним кодом.

Помічник міток

Мій інструмент TagHelper досить простий, все, що я роблю - це створюю <a> табличка з декількома атрибутами Я пізніше перейду в альпійський модуль і ми закінчили.

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

Параметри

У цьому випадку значення " очистити всі параметри " виглядає так. Я просто дивлюся на Context.Request.Query Якщо є будь-які параметри, я передаю "маленький" x піктограма, яка надає користувачеві змогу вилучити всі параметри.


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

Альтернативно для іменованих параметрів, я можу це зробити.


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

Що, звичайно ж, прояснило б цей єдиний параметр.

Або навіть


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

За допомогою цього пункту можна спорожнити всі вказані параметри з рядка.

The target attribute

YOu також має параметр, який слід передати target атрибут, який буде використано як hx-target атрибут. Цей пункт буде корисним, якщо ви бажаєте оновити певну частину сторінки з новим вмістом.


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

У моєму випадку (через те, що я написав його) #page-content Лови.

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

Результат

Результат у зображенні такого HTML:

  • Всі: Отже, ми отримуємо HTML з x-all attribute і no x-param атрибут.
<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>

  • Одинарна Ми отримуємо HTML з x-param attribute і no x-all атрибут.
<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>
  • Множина Ми отримуємо HTML з x-param атрибут з відокремленим комами рядком і ні x-all атрибут.
<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>

Кожен з них також має два альпійські властивості. x-data і x-on:click.prevent які використовуються для налаштування альпійського модуля і виклику функції для очищення параметрів.

Посмотрим, как это работает дальше...

Альпійський модуль

Це, звичайно ж, стало можливим за допомогою альпійського.js для налаштування нашого запиту і виконання програми HTMX.

Як ви можете бачити в коді нижче, я маю простий модуль, який займає path поточної сторінки, а потім використовує URL API для обробки рядка запиту (ви також можете передати його іншим чином з будь- якої причини:).

Потім ми отримуємо елемент, який було натиснуто і перевірити, чи має він елемент x-all attribute; якщо буде позначено цей пункт, всі параметри буде вилучено з адреси URL, у іншому випадку буде розділено на x-param атрибут за комами і вилучити всі ці параметри.

Потім ми створюємо новий URL з оновленим рядком запиту і використовуємо HTMX для надсилання запиту до цього 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;

The showAlert функція за допомогою SweetAlert2

Ви також помітите, що я називаю showAlert функція. Це проста обгортка навколо SweetAlert2 навантажувального індикатора, який я використовую в моєму проекті. Ви, звичайно, можете замінити це на те, що ви хочете зробити.

Це трохи кореговано з Востаннє ми це бачили.. Отже, я можу витягти showAlert function і зробити його доступним для зовнішніх модулів. Що я використаю в обох param-clearer модуль і hx-indicator модуль.

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;

Як нагадування для цього використовується path ключ до визначення коли сховати сигнал тривоги.

HTMX

Нарешті, ми використовуємо htmx.ajax зробити прохання. Це простий запит на отримання нової адреси URL, яку ми створили з оновленим рядком запиту.

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

Включення

Це простий спосіб спорожнити параметри URL за допомогою допоміжних засобів міток і альпійських. js. Він дозволяє очистити всі параметри, або лише специфічні, з мінімальним кодом.

logo

©2024 Scott Galloway