Ένας βοηθός ετικέτας Alpine.js και HTMX ενεργοποιήθηκε για ASP.NET Core ( ελληνικά (Greek_)

Ένας βοηθός ετικέτας Alpine.js και HTMX ενεργοποιήθηκε για ASP.NET Core

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 με πολλαπλές παραμέτρους, και θέλετε να αφαιρέσετε ένα ή περισσότερα από αυτά (για παράδειγμα ένα φίλτρο αναζήτησης).

Το Πρόβλημα

Το τρέχον πρότζεκτ μου χρησιμοποιεί παλιάς σχολής συμβολοσειρές ερωτημάτων (είναι ένας δικτυακός τόπος διαχείρισης, οπότε δεν χρειάζεται τη φαντασία των "καλών" URLs). Οπότε καταλήγω με ένα URL σαν αυτό:

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

Τώρα αυτά μπορούν να διαφέρουν με κάθε σελίδα, έτσι μπορώ να καταλήξω με ένα BUNCH στη σελίδα URL και πρέπει να είμαι σε θέση να τους καθαρίσει χωρίς να γράψετε ένα μάτσο λεβητοστάσιο για να το κάνουμε.

Μπορείτε να το κάνετε αυτό ως μέρος του οποιουδήποτε ελέγχου εισόδου που χρησιμοποιείτε έτσι για παράδειγμα δίπλα σε κάθε κουτί ελέγχου (ή ένα φανταχτερό στυλ placeholder σαφές εικονίδιο) αλλά μπορείτε να χρησιμοποιήσετε αυτή την τεχνική και για εκείνους επίσης. Ωστόσο, σε αυτή την περίπτωση ήθελα να κάνω δύο βασικά πράγματα:

  1. Να είστε σε θέση να καθαρίσετε μια χαρακτηριστική παράμετρο
  2. Να είστε σε θέση να καθαρίσετε μια λίστα παραμέτρων.
  3. Να είστε σε θέση να καθαρίσετε όλες τις παραμέτρους
  4. Να το στείλετε πίσω με HTMX
  5. Χρησιμοποίησε τον δείκτη φόρτωσης μου. ο δείκτης φόρτωσης μου.

Η Λύση

Στο πρόγραμμά μου χρησιμοποιώ ήδη

  • HTMX
  • Alpine.js
  • ASP.NET Core
  • Ανεμοστρόβιλος
  • DaisyUI

Έτσι, η λύση μου ήταν συγκεντρωμένη γύρω από τη χρήση αυτών για να πάρει μια όμορφη, λειτουργική λύση με ελάχιστο κώδικα.

Ο Βοηθός Ετικέτας

Το TagHelper μου είναι αρκετά απλό, το μόνο που κάνω είναι να δημιουργήσω ένα <a> Ετικέτα με μερικά χαρακτηριστικά που θα περάσω αργότερα στην Alpine Module και τελειώσαμε.

[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 έχετε επίσης την επιλογή να περάσει σε ένα 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 div.

    [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 χαρακτηριστικά γνωρίσματα με διαχωριστική συμβολοσειρά κόμμα και όχι 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 που χρησιμοποιούνται για τη δημιουργία της ενότητας των Άλπεων και καλούν τη λειτουργία να καθαρίσει τις παραμέτρους.

Θα δούμε πως θα πάει μετά...

Η Αλπική Ενότητα

Αυτό είναι φυσικά δυνατό μέσω της χρήσης των Alpine.js για να ρυθμίσετε το αίτημά μας και HTMX για να το εκτελέσετε.

Όπως μπορείτε να δείτε στον παρακάτω κώδικα, έχω μια απλή ενότητα που παίρνει το path της τρέχουσας σελίδας και στη συνέχεια χρησιμοποιεί το URL API για την ανάλυση της συμβολοσειράς ερωτημάτων (μπορείτε επίσης να περάσετε σε ένα διαφορετικό για οποιονδήποτε λόγο:)).

Στη συνέχεια, παίρνουμε το στοιχείο που κλικ και να ελέγξουμε αν έχει το x-all χαρακτηριστικό; εάν το κάνει διαγράφουμε όλες τις παραμέτρους από το 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;

Η showAlert λειτουργία χρησιμοποιώντας SweetAlert2

Θα σημειώσετε επίσης ότι εγώ ονομάζω... showAlert λειτουργία. Αυτό είναι απλά ένα απλό περιτύλιγμα γύρω από τον δείκτη φόρτωσης SweetAlert2 που χρησιμοποιώ στο έργο μου. Μπορείτε φυσικά να το αντικαταστήσετε αυτό με ό,τι θέλετε να κάνετε."

Αυτό είναι ελαφρώς tweaked από το Την τελευταία φορά που το είδαμε. Για να μπορέσω να βγάλω το... showAlert να λειτουργεί και να το καθιστά διαθέσιμο σε εξωτερικές ενότητες. Το οποίο ας το χρησιμοποιήσω και στα δύο. param-clearer ενότητα και hx-indicator module.

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 να υποβάλει το αίτημα. Αυτό είναι ένα απλό αίτημα GET στο νέο URL που δημιουργήσαμε με την ενημερωμένη συμβολοσειρά ερώτημα.

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

Συμπέρασμα

Αυτός είναι ένας απλός τρόπος για να καθαρίσετε τις παραμέτρους URL χρησιμοποιώντας έναν βοηθό ετικετών και Alpine.js. Σας επιτρέπει να καθαρίσετε όλες τις παραμέτρους, ή μόνο συγκεκριμένες, με ελάχιστο κωδικό.

logo

©2024 Scott Galloway