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
Une décharge de recherche plus intelligente avec HTMX
Monday, 16 September 2024
Introduction
Dans un précédent post je vous ai montré comment créer une descendre de recherche en utilisant Alpine.js et HTMX puis j'ai montré comment nous pouvions assurer la protection contre la fausse demande de site Cross- en utilisant le AntiforgeryRequestToken dans ASP.NET Core avec JavaScript Utiliser HTMX pour mettre en œuvre un cache Donut Hole. Une question en suspens était la façon dont les pages étaient chargées.
Le problème
Le problème était que je faisais appel à HTMX AJAX pour charger la page demandée une fois que vous avez sélectionné le résultat de la page descendante.
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'
});
});
Le problème était que, même si cela allait charger la page droite et mettre à jour l'URL montrée avec une nouvelle , il a défectué le bouton arrière. Comme la page WASNM SK2T REALLY loaded into the history properlyMSC3
Comme dans mon cas dernier article sur les shennanigans du bouton arrière c’est quelque chose que je voulais corriger.
La solution
Comme auparavant, la solution consistait à laisser HTMX traiter ce problème directement. Pour cela j’ai mis à jour mon modèle que je utilise pour les résultats de recherche.
_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>
Vous verrez que je vais maintenant générer intégralité Liens HTMX dans ce bloc de code. Ce qui nous permet d'utiliser le comportement correct HT MX.
typeahead.js
Pour ce faire dans mon code JavaScript de backend, j’ai ajouté ce qui suit à ma méthode de recherche ( montré ci-dessous). this.$nextTick est une construction Alpine.js qui retarde ce processus jusqu’à ce que l’Alpine ait terminé le traitement du modèle que j’ai montré ci-dessus
Je puis utiliser htmx.process() sur l'élément de recherche qui garantira que les attributs HTMX fonctionnent comme prévu.
.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
});
}
Cette option est sélectionnée en cliquant sur le lien dans les résultats de recherche.
<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>
Ce qui chargera ensuite la page et mettra à jour correctement l’URL.
J'ai également un code dans la case parentale qui vous permet d'utiliser les touches à flèche et de saisir.
<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>
Vous ' constaterez que ce fichier contient tous les codes nécessaires pour vous permettre de cliquer sur l’entrée et de naviguer vers la page sélectionnée.
En conclusion
Just a quick update article to the existing search dropdown to enhance the user experience when using search. Again this is a MINIMAL user facing change but just enhances the User Experience; who as a web developer are your primary concern M SK2beyond getting paid :)).