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
Σε μια προηγούμενη θέση σας έδειξα πώς να δημιουργήσετε ένα search dropdown using Alpine.js and HTMX τότε έδειξα πώς θα μπορούσαμε να ενεργοποιήσουμε Cross-Site Αίτηση προστασίας πλαστογραφίας χρησιμοποιώντας το AntiforgeryRequestToken
σε ASP.NET Core με JavaScript χρησιμοποιώντας HTMX για την εφαρμογή μιας κρύπτης Donut Hole. Ένα εξέχον ζήτημα ήταν το πώς φόρτωνε σελίδες.
Το θέμα ήταν ότι χρησιμοποιούσα HTMX AJAX για να κάνω την ζητούμενη φόρτωση σελίδας μόλις είχατε επιλέξει το αποτέλεσμα από την κάτω σελίδα. Αυτό μόνο η Κίντα δούλεψε.
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'
});
});
Το θέμα ήταν ότι ενώ αυτό θα φορτώσει τη σωστή σελίδα και την ενημέρωση της εμφανιζόμενης URL με το νέο, καταστράφηκε το πίσω κουμπί. Καθώς η σελίδα δεν ήταν πραγματικά φορτωμένη στην ιστορία σωστά.
Όπως και με το δικό μου τελευταίο άρθρο στο πίσω κουμπί Shennanigans Αυτό ήταν κάτι που ήθελα να διορθώσω.
Όπως και στο παρελθόν, η λύση ήταν να το χειριστεί άμεσα το HTMX. Για να το κάνω αυτό ενημέρωσα το πρότυπό μου που χρησιμοποιώ για τα αποτελέσματα αναζήτησης.
_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>
Θα δεις ότι τώρα δημιουργώ κατάλληλη Σύνδεσμοι HTMX σε αυτό το μπλοκ κώδικα. Αφήνοντας μας να χρησιμοποιήσουμε τη σωστή συμπεριφορά HTMX.
typeahead.js
Για να το ενεργοποιήσω αυτό στο backend μου JavaScript code πρόσθεσα τα ακόλουθα στη μέθοδο αναζήτησης μου (shown below). Η this.$nextTick
είναι μια κατασκευή Alpine.js που καθυστερεί αυτό μέχρι Alpine έχει τελειώσει την επεξεργασία του προτύπου που έδειξα παραπάνω.
Στη συνέχεια, χρησιμοποιώ htmx.process()
σχετικά με το στοιχείο αναζήτησης που θα εξασφαλίσει ότι τα χαρακτηριστικά HTMX λειτουργούν όπως αναμένεται.
.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
});
}
Αυτό επιλέγεται μέσω του κλικ του συνδέσμου στα αποτελέσματα αναζήτησης.
<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>
Το οποίο στη συνέχεια θα φορτώσει τη σελίδα και θα ενημερώσει σωστά το URL.
Έχω επίσης τον κωδικό στο παπιγιόν γονιών σας επιτρέπει να χρησιμοποιήσετε τα πλήκτρα βέλους και να εισάγετε.
<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>
Θα δείτε ότι αυτό έχει όλο τον κωδικό που είναι απαραίτητος για να σας επιτρέψει να χτυπήσετε απλά την είσοδο και την πλοήγηση στην επιλεγμένη σελίδα.
Απλά ένα γρήγορο άρθρο ενημέρωσης για την υπάρχουσα πτώση αναζήτησης για να ενισχύσει την εμπειρία του χρήστη κατά τη χρήση της αναζήτησης. Και πάλι αυτό είναι ένα MINIMAL χρήστη που αντιμετωπίζει την αλλαγή, αλλά απλά ενισχύει την εμπειρία του χρήστη; ο οποίος ως web developer είναι η κύρια ανησυχία σας (πέρα από την πληρωμή:)).