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.
Monday, 16 September 2024
//Less than a minute
I ett tidigare inlägg visade jag dig hur man skapar en sök dropdown med Alpine.js och HTMX Sedan visade jag hur vi kunde möjliggöra Cross-Site Request Forgery skydd med hjälp av AntiforgeryRequestToken
i ASP.NET Core med JavaScript med hjälp av HTMX för att implementera en Donut Hole-cache....................................... En av de viktigaste frågorna var hur den laddade sidor.
Problemet var att jag använde HTMX AJAX för att ladda den begärda sidan när du hade valt resultatet från rullgardinssidan. Det här fungerade bara 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'
});
});
Problemet var att medan detta skulle ladda rätt sida och uppdatera den visade webbadressen med den nya, det förstörde upp den bakre knappen. Eftersom sidan inte var riktigt laddad i historien korrekt.
Som med min förra artikeln på baksidan knapp shennanigans Det var något jag ville fixa.
Liksom tidigare var lösningen att låta HTMX hantera detta direkt. För att göra detta har jag uppdaterat min mall som jag använder för sökresultat.
_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>
Du kommer att se att jag nu genererar korrekt HTMX länkar i det här kodblocket. Låt oss använda rätt HTMX-beteende.
typeahead.js
För att aktivera detta i mitt gränssnitt JavaScript-kod lade jag till följande i min sökmetod (visas nedan). I detta sammanhang är det viktigt att se till att this.$nextTick
är en Alpine.js konstruktion som försenar detta tills Alpine har avslutat behandlingen av mallen jag visade ovan.
Jag använder sedan htmx.process()
på sökelementet som kommer att se till att HTMX-attributen fungerar som förväntat.
.then(data => {
this.results = data;
this.highlightedIndex = -1; // Reset index on new search
this.$nextTick(() => {
htmx.process(document.getElementById('searchresults'));
});
})
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
});
}
Detta väljs genom att klicka på länken i sökresultaten.
<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>
Som sedan kommer att ladda sidan och uppdatera webbadressen korrekt.
Jag har också kod i överliggande rutan whoick kan du använda piltangenterna och ange.
<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>
Du kommer att se att detta har alla de koder som krävs för att du bara ska kunna trycka på enter och navigera till den valda sidan.
Bara en snabb uppdatering artikel till den befintliga sök dropdown för att förbättra användarupplevelsen när du använder sökning. Återigen detta är en MINIMAL användare inför förändring men bara förbättrar användarupplevelsen, som som en webbutvecklare är din främsta oro (bortom att få betalt :)).