En Alpine.js och HTMX 'Klear söksträngparametern (sM SK3 taghelpare för ASPMSC4NET Core
Inleiding
Bara en snabb: , Jag hade ett behov i ett arbetsprojekt av att ha möjligheten att 'kla ut URL-parameter från en URL: n. This is useful when you have a URL with multiple parameters, and you want to remove one or more of them
Problemet
Mitt nuvarande projekt använder gamla urls.
/products?category=electronics&search=wireless+headphones&sort=price_desc&inStock=true&page=3
Nu kan dessa variera med varje sida, så jag kan ha en BUNCHE i sidans URL och jag behöver kunna ta bort dem utan att skriva upp en massa boilerplattor för att göra det.
Du kan göra detta som en del av vilket inmatningskontroll du än använder så till exempel bredvid varje checkbox ( eller ett fint placeholder-stilt tydliga ikoner ) men och du kan använda den här tekniken även för de där.
- Att kunna avlägsna ett namnget parametr
- Att kunna lösa en lista av parametrar.
- Att kunna städa alla parametrar
- få det att skicka tillbaka med HTMX
- Ska den använda min laddande indikator min laddande indikator.
Lösningen
I mitt projekt använder jag redan
- HTMX
- Alpine.js
- ASP.NET Core
- TailwindCSS
- DaisyUI
Så min lösning var fokuserad på att använda dessa för att få en trevlig utgångsbar funktionell lösning med minimal kod
Etikettbekymmern
Min TagHelper är ganska enkel, allt jag gör är att skapa en <a> tag med några attributer I' passerar senare in i Alpine Modulet och vi
[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>");
}
}
Parameter
I användandet ser det ut som detta, först för 'klara alla parametrar '. Så jag tittar bara på Context.Request.Query om det finns några parametrar där så renderar jag den lilla x ikon för att låta användaren avlägsna alla parametrar.
@if(Context.Request.Query.Any())
{
<label class="param-label">
<clear-param all="true"></clear-param>
clear all
</label>
}
</div>
Alternativt för namngeda parametrar kan jag göra detta
<div class="param-label">
<clear-param name="myParam"></clear-param>
<p>My Param: @Model.MyParam</p>
</div>
Vilket skulle förstås klargöra att den enda parametren
Eller till och med
<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>
Detta löser sedan alla namngeda parametrar från raden.
Den target attribut
Du har också möjligheten att gå igenom target attribut som kommer att användas som hx-target attribute. Detta är användbart om du vill uppdatera en specifik del av sidan med den nya innehållet
<div class="param-label">
<clear-param name="myParam" target="#my-thing"></clear-param>
<p>My Param: @Model.MyParam</p>
</div>
I mitt fall ( eftersom jag skrev det ) så valde jag målet som standard #page-content div.
[HtmlAttributeName("target")]
public string Target { get; set; } = "#page-content";
Resultatet
De resulterar i att vi visar följande HTML:
- Alla:
Så vi får HTML med
x-allattribut och ingetx-paramattribute.
<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>
- Enkel
Vi får HTML med
x-paramattribut och ingetx-allattribute.
<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>
- Multipla
Vi får HTML med
x-paramattribut med en komma separat string och ingetx-allattribute.
<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>
Var och en av dem har också de två alpina egenskaperna x-data och x-on:click.prevent som används för att installera Alpine-modulet och ropa på funktionen för att avgöra parametrerna.
Vi ska se hur det fungerar härnäst.
Alpine Modulet
Detta är förstås möjligt genom att använda Alpine.js för att konfigurera vår begäran och HTMX för att utföra den
Som ni kan se i koden härunder, har jag ett enkelt modul som tar path av den nuvarande sidan och använder sedan URL API för att analysera sökstringen ( du kan också skicka in en annan av någon anledning
Sedan tar vi elementet som klickats på och ser om det har x-all attribute; om det gör att vi löser alla parametrar från URL, annars delar vi upp x-param attribut med kommas och radera varenda en av dessa parametrar.
Sedan skapar vi en ny URL med den uppdaterade söktråden och använder HTMX för att göra ett begäran till den 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;
Den showAlert funktionen med SweetAlert2
Du "'" kommer också märka att jag showAlert funktion. Det här är bara en enkel förpackning runt SweetAlert 2 laddande indikator som jag använder i mitt projekt
Det här är lite för twäckat från den sista gången vi såg det. Så jag kunde extrahera showAlert och göra den tillgänglig för externa moduler. som låter mig param-clearer modul och hx-indicator modul.
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;
Som en påminnelse använder detta path som nyckeln till att veta när man ska dölja larmet.
HTMX
Slutligen använder vi htmx.ajax att göra utmaningen. Det här är en enkel GET utmaning till den nya URL som vi skapade med den uppdaterade söksträngen
htmx.ajax('GET', newUrl, {
target: el.dataset.target || el.getAttribute('hx-target') || 'body',
swap: 'innerHTML',
pushUrl: true
});
I slutsats
Det här är ett enkelt sätt att avlägsna URL-parameter med hjälp av en taghelpare och Alpine.