javascripthtmleleventy

Search functionality in 11ty


I am building a basic search functionality on an 11ty site based on this tutorial. My problem is when I type the form and submit it, it will take me to another site even though I included preventDefault() in the code. Did I miss out on the steps or is there are better ways of implementing the feature into the site?

Here's my code and link to a demo site:

(function (window, document, undefined) {
    'use strict';
    let form = document.querySelector('#form-search');
    let input = document.querySelector('#search-input');
    let resultList = document.querySelector('#search-results');

    /**
     * Create the HTML for each result
     * @param  {Object} article The article
     * @param  {Number} id      The result index
     * @return {String}         The markup
     */
    let createHTML = function (article, id) {
        let html =
            '<div id="search-result-' + id + '">' +
                '<a href="' + article.url + '">' +
                    '<aside>' +
                        article.date +
                    '</aside>' +
                    '<h2>' + article.title + '</h2>' +
                    article.summary.slice(0, 150) + '...<br>' +
                    article.url +
                '</a>' +
            '</div>';
        return html;
    };

    /**
     * Create the markup when no results are found
     * @return {String} The markup
     */
    let createNoResultsHTML = function () {
        return '<p>Sorry, no matches were found.</p>';
    };

    /**
     * Create the markup for results
     * @param  {Array} results The results to display
     * @return {String}        The results HTML
     */
    let createResultsHTML = function (results) {
        let html = '<p>Found ' + results.length + ' matching articles</p>';
        html += results.map(function (article, index) {
            return createHTML(article, index);
        }).join('');
        return html;
    };

    /**
     * Search for matches
     * @param  {String} query The term to search for
     */
    let search = function (query) {

        // Variables
        let reg = new RegExp(query, 'gi');
        let priority1 = [];
        let priority2 = [];

        // Search the content
        searchIndex.forEach(function (article) {
            if (reg.test(article.title)) return priority1.push(article);
            if (reg.test(article.blogTitle)) priority2.push(article);
        });

        // Combine the results into a single array
        let results = [].concat(priority1, priority2);

        // Display the results
        resultList.innerHTML = results.length < 1 ? createNoResultsHTML() : createResultsHTML(results);

    };

    /**
     * Handle submit events
     */
    let submitHandler = function (event) {
        event.preventDefault();
        search(input.value);
    };

    // Make sure required content exists
    if (!form || !input || !resultList || !searchIndex) return;

    // Create a submit handler
    form.addEventListener('submit', submitHandler);

})(window, document);
<section id="hero">
    <div class="container">
        <div class="hero-buttons">
        <h1 class="blog-header">11ty Search Demo</h1>
        <form action="https://duckduckgo.com/" method="get" id="form-search">
            <input class="search-input" placeholder="Search here..." />
            <input type="hidden" name="sites" value="https://11ty-search-demo.netlify.app/">
            <button class="submit-search">Search</button>
        </form>
        <div id="search-results"></div>
        </div>
    </div>
</section>

<section id="blog">
    <div class="container">
        {%- for post in collections.post | reverse -%} {% include
        'recent-snippet.njk' %} {%- endfor -%}
    </div>
</section>

Demo link: https://11ty-search-demo.netlify.app/

Code Sandbox: Link


Solution

  • After debugging the code, the issue was traced to the following line:

    if (!form || !input || !resultList || !searchIndex) return;
    

    In this segment, you are checking whether any of the values in the if condition are false. If that's the case, the function will either return false or undefined. The problem arises because your input variable is undefined, causing the entire function to evaluate as false. Consequently, the subsequent line of code fails to execute:

    form.addEventListener('submit', submitHandler);
    

    This unexecuted line is responsible for handling the form submission. As a result, your form is being submitted unexpectedly.

    The reason behind the input variable being undefined lies in the selector you used. Instead of using an id, you mistakenly used a class selector. For instance, you used this:

    let input = document.querySelector('#search-input');
    

    However, it should be like this:

    let input = document.querySelector('.search-input');
    

    This corrected selector targets the element with the class name search-input, ensuring that the input variable receives the intended element.

    To visualize the solution in action, you can refer to this functional example.