This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Een slimmere zoekopspring met HTMX
Monday, 16 September 2024
Inleiding
In een vorige post toonde ik jullie hoe je een Search dropdown met Alpine.js en HTMX Toen toonde ik hoe we Cross-Site Request Vervalsbescherming konden toepassen met behulp van de AntiforgeryRequestToken in ASP.NET Core met JavaScript Met HTMX implementeren we een Donut Hole Cache.. Een probleem was hoe het pagina's laadde.
Het probleem
Het probleem was dat ik HTMX AJAX gebruikte om de aangevraagde pagina te laden nadat je het resultaat uit de afvalpagina had gekozen.. Dit werkte alleen bij KINDA.
selectResult(result) {
htmx.ajax('get', result.url, {
target: '#contentcontainer', // The container to update
swap: 'innerHTML', // Replace the content inside the target
}).then(function() {
history.pushState(null, '', result.url);
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
Het probleem was dat terwijl dit de juiste pagina laadde en de vertoonde URL met een nieuwe aktualiseerde, het de achterkant van de knop verstoordeM SK1 Omdat de pagina WASN' Wél correct in de geschiedenis geladen was .
Zoals bij mij. laatste artikel over 'back button shennanigans' Dit was iets dat ik wilde repareren.
De oplossing
Zoals vroeger was de oplossing om HTMX dit direct te laten beheren. Om dit te doen heb ik mijn werkvoorbeeld opgedateerd dat ik gebruik voor zoekresultaten.
_typeahead.cshtml
<div x-data="window.mostlylucid.typeahead()" class="relative" id="searchelement" x-on:click.outside="results = []">
@Html.AntiForgeryToken()
<label class="input input-sm bg-neutral-500 bg-opacity-10 input-bordered flex items-center gap-2">
<input
type="text"
x-model="query"
x-on:input.debounce.200ms="search"
x-on:keydown.down.prevent="moveDown"
x-on:keydown.up.prevent="moveUp"
x-on:keydown.enter.prevent="selectHighlighted"
placeholder="Search..."
class="border-0 grow input-sm text-black dark:text-white bg-transparent w-full"/>
<i class="bx bx-search"></i>
</label>
<!-- Dropdown -->
<ul x-show="results.length > 0"
id="searchresults"
class="absolute z-100 my-2 w-full bg-white dark:bg-custom-dark-bg border border-1 text-black dark:text-white border-neutral-600 rounded-lg shadow-lg">
<template x-for="(result, index) in results" :key="result.slug">
<li :class="{
'dark:bg-blue-dark bg-blue-light': index === highlightedIndex,
'dark:hover:bg-blue-dark hover:bg-blue-light': true
}"
class="cursor-pointer text-sm p-2 m-2">
<!-- These are the key changes.-->
<a
x-on:click="selectResult(index)"
@* :href="result.url" *@
:hx-get="result.url"
hx-target="#contentcontainer"
hx-swap="innerHTML"
hx-push-url="true"
x-text="result.title"
>
</a>
<-- End of changes -->
</li>
</template>
</ul>
</div>
Je zal zien dat ik nu genereer. Gepaste HTMX-verbindingen in dit codeblok. Laat ons het juiste HT MX-gedrag gebruiken.
typeahead.js
Om dit in mijn backend JavaScript-code te doen, voegde ik de volgende toe aan mijn zoekmethode: (vertoond onder this.$nextTick is een Alpine.js constructie die dit vertraagt totdat Alpine het werkvoorbeeld dat ik liet zien, klaar heeft.
Ik gebruik dan htmx.process() op het zoekelement dat ervoor zorgt dat de HTMX-attributen werken zoals verwacht.
.then(data => {
this.results = data;
this.highlightedIndex = -1; // Reset index on new search
this.$nextTick(() => {
htmx.process(document.getElementById('searchresults'));
});
})
typeahead.js search
search() {
if (this.query.length < 2) {
this.results = [];
this.highlightedIndex = -1;
return;
}
let token = document.querySelector('#searchelement input[name="__RequestVerificationToken"]').value;
console.log(token);
fetch(`/api/search/${encodeURIComponent(this.query)}`, { // Fixed the backtick and closing bracket
method: 'GET', // or 'POST' depending on your needs
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': token // Attach the AntiForgery token in the headers
}
})
.then(response => {
if(response.ok){
return response.json();
}
return Promise.reject(response);
})
.then(data => {
this.results = data;
this.highlightedIndex = -1; // Reset index on new search
this.$nextTick(() => {
htmx.process(document.getElementById('searchresults'));
});
})
.catch((response) => {
console.log(response.status, response.statusText);
if(response.status === 400)
{
console.log('Bad request, reloading page to try to fix it.');
window.location.reload();
}
response.json().then((json) => {
console.log(json);
})
console.log("Error fetching search results");
});
}
selectHighlighted() {
if (this.highlightedIndex >= 0 && this.highlightedIndex < this.results.length) {
this.selectResult(this.highlightedIndex);
}
},
selectResult(selectedIndex) {
let links = document.querySelectorAll('#searchresults a');
links[selectedIndex].click();
this.$nextTick(() => {
this.results = []; // Clear the results
this.highlightedIndex = -1; // Reset the highlighted index
this.query = ''; // Clear the query
});
}
Dit wordt gekies door het opklikken van de link in de zoekresultaten.
<a
x-on:click="selectResult(index)"
:hx-get="result.url"
hx-target="#contentcontainer"
hx-swap="innerHTML"
hx-push-url="true"
x-text="result.title"
>
</a>
Wat dan de pagina laadt en de URL correct aktualiseert.
Ik heb ook code in de oudere doos waarmee je de pijlsleutels kunt gebruiken en invoert.
<label class="input input-sm bg-neutral-500 bg-opacity-10 input-bordered flex items-center gap-2">
<input
type="text"
x-model="query"
x-on:input.debounce.200ms="search"
x-on:keydown.down.prevent="moveDown"
x-on:keydown.up.prevent="moveUp"
x-on:keydown.enter.prevent="selectHighlighted"
placeholder="Search..."
class="border-0 grow input-sm text-black dark:text-white bg-transparent w-full"/>
<i class="bx bx-search"></i>
</label>
Je zal zien dat dit alle nodige code heeft om je te laten invoeren en navigeren naar de gekose pagina.
In slotting:
Gewoon een snelle update-artikel naar de bestaande zoekoplaai om het gebruikerservaring te verbeteren bij het gebruik van zoeken. Nogmaals, dit is een MINIMAL gebruiker met verandering te maken maar alleen het gebruikersleven verbetert.