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
فقط واحدة سريعة، كان لي حاجة في مشروع عمل من أجل القدرة على "توضيح" بارامترات URL من URL. هذا مفيد عندما يكون لديك URL مع متعدد البارامترات، وتريد إزالة واحد أو أكثر منهم (على سبيل المثال لمرشح بحث).
مشروعي الحالي يستخدم شروط استعلام المدرسة القديمة (إنه موقع إداري لذلك لا يحتاج إلى خيالية "nice" urls). لذا سأنتهي مع عنوان مثل هذا:
/products?category=electronics&search=wireless+headphones&sort=price_desc&inStock=true&page=3
الآن هذه يمكن أن تختلف مع كل صفحة، حتى أستطيع أن ينتهي بي الأمر مع BUNCH في صفحة URL وأنا بحاجة إلى أن تكون قادرة على مسحها من دون كتابة مجموعة من المرجل للقيام بذلك.
يمكنك أن تفعل هذا كجزء من أي من التحكم في المدخلات الذي تستخدمه لذلك على سبيل المثال إلى جانب كل صندوق شيك (أو أيقونة واضحة على نمط faile profile) ولكن يمكنك استخدام هذه التقنية لتلك أيضا. ومع ذلك، في هذه الحالة أردت أن أفعل شيئان رئيسيان:
في مشروعِي أَستعملُ
لذا كان حلي مركزاً حول استخدام هذه للحصول على حل عملي وجميل مع الحد الأدنى من الشفرة.
مُحَجّتي بسيطة جداً، كل ما أفعله هو إنشاء <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>
هذا يوضّح كلّ مُسمّى المُعاملات من السلسلة.
targetYOu أيضاً لديها الخيار للمرور في 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 التالي:
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>
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>
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 كمفتاح لمعرفة متى نخفي التنبيه
وأخيراً، نستعمل htmx.ajax لتقديم الطلب. هذا هو a بسيط طلب get إلى جديد URL نحن مع مُحدّث إقتراح سلسلة نص.
   htmx.ajax('GET', newUrl, {
                target: el.dataset.target || el.getAttribute('hx-target') || 'body',
                swap: 'innerHTML',
                pushUrl: true
            });
هذه طريقة بسيطة لمسح بارامترات الواجهة باستخدام مساعد بطاقة و Alpin.js. يسمح لك بمسح جميع البارامترات، أو فقط محددات، مع رمز الحد الأدنى.