Ajax/jQuery autocomplete in search box (Shopify)

Multi tool use
Multi tool use


Ajax/jQuery autocomplete in search box (Shopify)



I am looking to get autocomplete setup on my search bars within my Shopify shop- this uses Liquid and ajax



I found this tutorial, and implemented it as it says, however it is not working, nothing gets autocompleted on any search bar on the site- I think it may be quite old and was written before the updates/changes to Minimal/Shopify search functionality.



https://help.shopify.com/themes/customization/store/enable-autocomplete-for-search-boxes



I can follow it through with Chrome dev tools, and it seems like it gets stuck where it adds the search-results list $('<ul class="search-results"></ul>').appendTo($(this)).hide();, this doesn't appear when tracing the HTML of the page. This means that when it later tries to find this list var resultsList = form.find('.search-results'); it doesn't find it, and thus cannot populate with items.


$('<ul class="search-results"></ul>').appendTo($(this)).hide();


var resultsList = form.find('.search-results');



I am running the Minimal theme.
The website is testing site with the search bar on the top grey header, and also on /search



A test site built by Shopify to demo this autocomplete is located [https]://search-autocomplete.myshopify.com/. The <ul> append is already there on page load.


<ul>



EDIT:



Doing a bit more digging, I stumbled across this error in the dev tools -



Uncaught ReferenceError: jQuery is not defined at (index):7031



Which is, you guessed it, the first line of the jQuery code below. $(function() { Any idea why the jQuery is undefined? The script is included at the bottom of my index file right before </body>, so the jquery.min.js should have loaded by then, the rest of the jQuery on the site works fine.


$(function() {


</body>



Form code on testing site


<form action="/search" method="get" class="site-header__search small--hide" role="search">
{% comment %}<input type="hidden" name="type" value="product">{% endcomment %}
<div class="site-header__search-inner">
<label for="SiteNavSearch" class="visually-hidden">{{ 'general.search.placeholder' | t }}</label>
<input type="search" name="q" id="SiteNavSearch" placeholder="{{ 'general.search.placeholder' | t }}" aria-label="{{ 'general.search.placeholder' | t }}" class="site-header__search-input">
</div>

<button type="submit" class="text-link site-header__link site-header__search-submit">
{% include 'icon-search' %}
<span class="icon__fallback-text">{{ 'general.search.submit' | t }}</span>
</button>
</form>



search.json


{% layout none %}
{% capture results %}
{% for item in search.results %}
{% assign product = item %}
{
"title" : {{ product.title | json }},
"url" : {{ product.url | within: product.collections.last | json }},
"thumbnail": {{ product.featured_image.src | product_img_url: 'thumb' | json }}
}
{% unless forloop.last %},{% endunless %}
{% endfor %}
{% endcapture %}
{
"results_count": {{ search.results_count }},
"results": [{{ results }}]
}



search-autocomplete.liquid


<script>
$(function() {
// Current Ajax request.
var currentAjaxRequest = null;

// Grabbing all search forms on the page, and adding a .search-results list to each.
var searchForms =
$('form[action="/search"]').css('position','relative').each(function() {

// Grabbing text input.
var input = $(this).find('input[name="q"]');

// Adding a list for showing search results.
var offSet = input.position().top + input.innerHeight();
$('<ul class="search-results"></ul>').css( { 'position': 'absolute', 'left': '0px', 'top': offSet } ).appendTo($(this)).hide();

// Listening to keyup and change on the text field within these search forms.
input.attr('autocomplete', 'off').bind('keyup change', function() {

// What's the search term?
var term = $(this).val();

// What's the search form?
var form = $(this).closest('form');

// What's the search URL?
var searchURL = '/search?type=product&q=' + term;

// What's the search results list?
var resultsList = form.find('.search-results');

// If that's a new term and it contains at least 3 characters.
if (term.length > 3 && term != $(this).attr('data-old-term')) {

// Saving old query.
$(this).attr('data-old-term', term);

// Killing any Ajax request that's currently being processed.
if (currentAjaxRequest != null) currentAjaxRequest.abort();

// Pulling results.
currentAjaxRequest = $.getJSON(searchURL + '&view=json', function(data) {
// Reset results.
resultsList.empty();

// If we have no results.
if(data.results_count == 0) {

// resultsList.html('<li><span class="title">No results.</span></li>');
// resultsList.fadeIn(200);
resultsList.hide();
} else {

// If we have results.
$.each(data.results, function(index, item) {
var link = $('<a></a>').attr('href', item.url);
link.append('<span class="thumbnail"><img src="' + item.thumbnail + '" /></span>');
link.append('<span class="title">' + item.title + '</span>');
link.wrap('<li></li>');
resultsList.append(link.parent());
});

// The Ajax request will return at the most 10 results.
// If there are more than 10, let's link to the search results page.
if(data.results_count > 10) {
resultsList.append('<li><span class="title"><a href="' + searchURL + '">See all results (' + data.results_count + ')</a></span></li>');
}
resultsList.fadeIn(200);
}
});
}
});
});

// Clicking outside makes the results disappear.
$('body').bind('click', function(){
$('.search-results').hide();
});
});
</script>




1 Answer
1



Here for posterity and completeness.



I finally got it working, with a few adjustments.



To fix the jQuery undefined error I replaced the first line with:
window.onload = (function() {


window.onload = (function() {



For some reason the results list was getting a display:block from somewhere, but I couldn't find it, so using jQuery I changed this to block which made it appear. Also in this code line I modified the term.length to start ajax requests on 2, else if you typed cat/dog you would need to then type another letter, or a space to start the search.


term.length



// If that's a new term and it contains at least 2 characters.
if (term.length > 2 && term != $(this).attr('data-old-term')) {
$('<ul class="search-results"></ul>').css( { 'display': 'block'} )


// If that's a new term and it contains at least 2 characters.
if (term.length > 2 && term != $(this).attr('data-old-term')) {
$('<ul class="search-results"></ul>').css( { 'display': 'block'} )



The search results now show up, and all correct! Just needs a bit of CSS adjustments for positioning.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

I8ovrGJaug6AT 6zFTWhSY 9sfA90hvE85BUDqYYhPQ5dhmFnZqoF0fTTg5,H1jroKhS
4,v yIHuXZEFzrm iuH9aDs8

Popular posts from this blog

Rothschild family

Cinema of Italy