Alpin.js و HTMX مساعد و بطاقة مساعدة مساعدة لمساعدة ASP.net (العربية (Arabic))

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

//

7 minute read

أولاً

فقط واحدة سريعة، كان لي حاجة في مشروع عمل من أجل القدرة على "توضيح" بارامترات URL من URL. هذا مفيد عندما يكون لديك URL مع متعدد البارامترات، وتريد إزالة واحد أو أكثر منهم (على سبيل المثال لمرشح بحث).

المشكلة

مشروعي الحالي يستخدم شروط استعلام المدرسة القديمة (إنه موقع إداري لذلك لا يحتاج إلى خيالية "nice" urls). لذا سأنتهي مع عنوان مثل هذا:

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

الآن هذه يمكن أن تختلف مع كل صفحة، حتى أستطيع أن ينتهي بي الأمر مع BUNCH في صفحة URL وأنا بحاجة إلى أن تكون قادرة على مسحها من دون كتابة مجموعة من المرجل للقيام بذلك.

يمكنك أن تفعل هذا كجزء من أي من التحكم في المدخلات الذي تستخدمه لذلك على سبيل المثال إلى جانب كل صندوق شيك (أو أيقونة واضحة على نمط faile profile) ولكن يمكنك استخدام هذه التقنية لتلك أيضا. ومع ذلك، في هذه الحالة أردت أن أفعل شيئان رئيسيان:

  1. إلى جاري حذف a مُسم
  2. تكون قادراً على توضيح قائمة البارامترات.
  3. يكون قادراً على توضيح جميع البارامترات
  4. احفظها مع HTMX
  5. استخدمها لمؤشر تحميلي - - - - - - - - - - - - - - - - - - -.

الإحلال

في مشروعِي أَستعملُ

  • XXXX
  • الألابين
  • المجموع الأساسي
  • تالوندسSSSS
  • رابعاً - الديزي

لذا كان حلي مركزاً حول استخدام هذه للحصول على حل عملي وجميل مع الحد الأدنى من الشفرة.

& مُفك مُفك مُحرف

مُحَجّتي بسيطة جداً، كل ما أفعله هو إنشاء <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>

هذا يوضّح كلّ مُسمّى المُعاملات من السلسلة.

الـ target

YOu أيضاً لديها الخيار للمرور في a 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 (السند و لا 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 (السند و لا 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 مع a فاصلة مقطوعة سلسلة نص و لا 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>

كل واحد منهم أيضاً له أيضاً الخاصتان Albines x-data وقد عقد مؤتمراً بشأن x-on:click.prevent التي تُستخدم لوضع وحدة الألب وتُسمّى الدالة لتوضيح البارامترات.

سنرى كيف سيسير ذلك لاحقاً...

الـ الـ من وحدة

هذا ممكن بالطبع من خلال استخدام الألبين.js لتهيئة طلبنا و HTMX لأداء ذلك.

كما ترون في الرمز أدناه، لدي وحدة بسيطة تأخذ path في الصفحة الحالية ومن ثم تستخدم URL API لطرح سلسلة الإستفسار (يمكنك أيضاً أن تمر في مكان مختلف لأي سبب كان :)

ثم نحصل على العنصر الذي تم النقر ونتحقق اذا كان لديه x-all الدالة، إذا كانت تفعل ذلك، نحذف كل هذه المعاملات من الواجهة، أو نقسمها x-param وحذف كل من هذه البارامترات.

ثم ننشئ عنواناً جديداً مع سلسلة الإستفسارات المحدثة واستخدام HTMX لجعل طلب إلى ذلك العنوان.

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 الدالة الدالة الدالة الدالة

وستلاحظ أيضاً أنني أدعو showAlert الدالة الدالة. هذه مجرد غلاف بسيط حول مؤشر تحميل سويت ألبيرت 2 الذي أستخدمه في مشروعي يمكنك بالطبع إستبدال هذا بكل ما تريد فعله

هذا قليلاً ما تم تعديله من في الوقت الذي رأيناه فيه/ / / / حتى أتمكن من استخراج showAlert (ب) أن تتيحه للوحدات الخارجية. والذي دعوني استخدمه في كلا 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 كمفتاح لمعرفة متى نخفي التنبيه

XXXX

وأخيراً، نستعمل htmx.ajax لتقديم الطلب. هذا هو a بسيط طلب get إلى جديد URL نحن مع مُحدّث إقتراح سلسلة نص.

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

في الإستنتاج

هذه طريقة بسيطة لمسح بارامترات الواجهة باستخدام مساعد بطاقة و Alpin.js. يسمح لك بمسح جميع البارامترات، أو فقط محددات، مع رمز الحد الأدنى.

logo

©2024 Scott Galloway