سحب بحث أذكى مع HTMX (العربية (Arabic))

سحب بحث أذكى مع HTMX

Monday, 16 September 2024

//

5 minute read

المقدمة

في پست سابق أريتكم كيف تصنع سحب البحث باستخدام Alpine.js وHTMX ثم أريتكم كيف يمكننا تشغيل "Cross-Site Request Forgery protection" باستخدام AntiforgeryRequestToken في ASP.NET Core مع JavaScript باستخدام HTMX لتطبيق مخزن ثقب دونات. واحدة من القضايا outstanding كانت كيفية تحميل الصفحات

المشكلة

المشكلة كانت أنني كنت أستخدم 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 المعروض مع واحد جديد , قد مزعج الزر الخلفي . كما أن الصفحة WASN' T حقاً تم تحميلها في التاريخ بصورة صحيحة .

كما هو الحال مع آخر مقالة عن الزر الخلفي للشنينغان هذا شيء أردت إصلاحه

الحل

كما هو الحال في السابق، كان الحل هو أن نترك 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 في هذا بلاك الشيفرة. يسمح لنا باستخدام سلوك HT MX الصحيح.

typeahead.js

لتشغيل هذا في شفرة جاواScript الخلفية خاصتي قمت بإضافة ما يلي إلى طريقة بحثي (مظهرة من الأسفل). this.$nextTick هو بناء ألبين .js الذي يؤجل هذا حتى قام ألبين بإنهاء معالجة النموذج الذي عرضته سابقاً .

ثم أستخدم htmx.process() على عنصر البحث الذي سيضمن أن خصائص HTMX تعمل كما هو متوقع.


.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
            });
        }

هذا يتم اختياره من خلال النقر على الروابط في نتائج البحث.

 <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>

ستلاحظون أن هذا يحتوي على كل البرمجة اللازمة لتتمكنوا من الضغط فقط على "إدخال" والانتقال إلى الصفحة المختارة

في الختام

مجرد تحديث سريع لكتابة البحث الموجودة لتحسين تجربتك المستخدمة عند استخدام البحث. مرة أخرى هذا هو مستخدم صغير يواجه التغيير ولكن فقط يحسن تجربته المستخدمة; الذين كمطور للويب هم اهتمامك الأولي M SK2 بجانب الحصول على المال :)).

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.