Predictive search API

Highlighted
Shopify Partner
111 8 37

Dear community,

I hope someone can help me here how to start with implementing the predictive search.

I'm not sure how and where to implement the JQuery call. I use minimal theme, the code in my search-bar.liquid looks like this

{% if search-bar == 'header' %}
  <form action="{{ routes.search_url }}" method="get" class="header-bar__search-form clearfix" role="search">
    {% comment %}<input type="hidden" name="type" value="product">{% endcomment %}
    <button type="submit" class="btn btn--search icon-fallback-text header-bar__search-submit">
      <span class="icon icon-search" aria-hidden="true"></span>
      <span class="fallback-text">{{ 'general.search.submit' | t }}</span>
    </button>
    <input type="search" name="q" value="{{ search.terms | escape }}" aria-label="{{ 'general.search.placeholder' | t }}" class="header-bar__search-input" placeholder="{{ 'general.search.placeholder' | t }}">
  </form>

I want to start implementing this code of the shopify Predictive Search API reference

jQuery.getJSON("/search/suggest.json", {
  "q": "jacket",
  "resources": {
    "type": "product",
    "limit": 4,
    "options": {
      "unavailable_products": "last",
      "fields": "title,product_type,variants.title"
    }
  }
}).done(function(response) {
  var productSuggestions = response.resources.results.products;

  if (productSuggestions.length > 0) {
    var firstProductSuggestion = productSuggestions[0];

    alert("The title of the first product suggestion is: " + firstProductSuggestion.title);
  }
});

do I have to replace the form? As I understood, what is new since June 2019, is that the API can be connected with storefront search, so I can implement the JQuery call in the existing header search-bar, right?

I'd be very happy for some input here.

Thank you!

Simonski

0 Likes
Highlighted
Shopify Partner
111 8 37

Finally I got my first successful response of my JQuery. This was a hard fight.

I'm honestly disappointed of the shopify tutorials and the support here. I don't understand why you guys post a "tutorial" of the Predictive Search and API reference and tell people "Here you can implement Predictive Search, where it doesn't explain anything how to implement that. It would need just a few more explanations and code!!! I know I'm a beginner, but many of your customers are! And giving hope that it would be easy to implement Predictive Search without explaining how is not the way to do. 

I'm talking about this

https://shopify.dev/tutorials/add-predictive-search-to-your-shopify-theme

https://shopify.dev/docs/themes/ajax-api/reference/predictive-search

 

For all the others, not to go almost mad as I did:

In your theme.liquid file, just above your closing body tag </body>, paste this:

<script>
      var q = 'YOUR_SEARCH_EXPRESSION'
      var b = '&resources[type]=product'
      $.ajax('/search/suggest.json?q=' + q + b,{
        type: 'GET',
        dataType: 'json', // added data type
        success: function(response) {
            console.log(response);
          	var productSuggestions = response.resources.results.products;
          	if (productSuggestions.length > 0) {
    			var firstProductSuggestion = productSuggestions[0];
            	alert(firstProductSuggestion.body);
          	}
      	}
      });
</script>
If it's not working, check if your JQuery is loaded correctly:
 <script>
 if (window.jQuery) {  
        // jQuery is loaded  
        alert("Yeah!");
    } else {
        // jQuery is not loaded
        alert("Doesn't Work");
    }
 </script>
Put all the scripts above your closing body tag.
0 Likes
Highlighted
Tourist
4 0 1

Hey @simonski , I'm still struggling to get this working. It's maddening that Shopify does not provide noob friendly tutorials. Could you please paste the relevant area of your theme.liquid so that I can see the context of what you did?

Also: Does the predictive search work for you the moment you enter something in the search field? I got it to work for me when I submitted the search, but that is not exactly the idea behind predictive search :-/

0 Likes
Highlighted
Shopify Partner
111 8 37

Howdy Django!

Basically what I did, I used the code for autocomplete search of this dude here:

https://www.huratips.com/tech-tips/how-to-add-autocomplete-for-search-boxes-to-your-shopify-store.ht...

After the line "What's the search term"

var term = $(this).val();

.. you put in my JQuery call of my last post. You have the search input in Huratips code. So you start typing "f" in your search box, the code executes and "term" is "f". You continue with "o", the code executes again, "term" is "fo" and so on. So you replace 

var q = 'YOUR_SEARCH_EXPRESSION'

 of my code with his line "var term...", but replace it with 

var q = $(this).val();

My code is meanwhile wrapped in lots of stuff with classes and css which won't work on your shop.

But my success answer looks like this:

'success': function(data) {
            var productSuggestions = data.resources.results.products;
            }

and to integrate in Huratips code, I use

 // If we have results.
            $.each(data.resources.results.products, function(index, item) {

You can check whats happening in "data" with console.log(data) to get all the results and write it in the results list, basically what Huratips is doing.

Hope this helps! It took me a really long time to find out this stuff. 

Highlighted
Tourist
5 0 0

Hey Simonski,

I understand what is happening in this code. I tried to implement this but the productSuggestions variable that you created is outside of scope of the Ajax call and i am not able to integrate it with the huratips code.

Please help me to fix this. It would be really helpful if you can share your working code. 

I have attached my code below.

 

      // What's the search term?
      var term = $(this).val();
      var b = '&resources[type]=product'
      $.ajax('/search/suggest.json?q=' + term + b,{
        type: 'GET',
        dataType: 'json', // added data type
        success: function(data) {
            var productSuggestions = data.resources.results.products;
            console.log(data);
            }
        
      });
            

      // 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.resources.results.products, 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();
  });
});

 

0 Likes
Highlighted
Shopify Partner
111 8 37

Hey Rohan,

ok I'll post my predictice search code, I did quite some adjustments in order to always adjust the size of the search-results box width for example. I hope you find the error in your file!

   <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"]');
     var breite = $(this).css('width');
     var offSet = 31;
     if ($(this).closest("div").hasClass("search-bar-desktop")){
       breite = 360;
       } else {
         offSet = $('.search-bar-mobile').actual('innerHeight');
         breite = $('.search-bar-mobile').actual('innerWidth');
         if (breite < 100) {
 		   offSet = 31;
           breite = 300;
         }
     }
     var breite2 = breite - 50;
     breite2 = breite2 + 'px';
// Adding a list for showing search results.
    $('<ul class="search-results"></ul>').css({ 
      'position': 'absolute', 
      'left': '0px', 
      'top': offSet,
      'width': breite +'px'
    }).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?
     //Wenn Breite nicht 360 ist (bei desktop) und nicht der inner width (mobile)
     //wird die Breite der Box hier angepasst (zb nach dynamischer animierter Veränderung)
     //möglich wäre hier auch, wenn dies hier nicht funzt, die Abfrage der aktuellen 
     //width von ul ".search-results"
     //entspricht diese (ohne "px") nicht der actual inner width, dann anpassen
     if( (breite != 360) && (breite != $('.search-bar-mobile').actual('innerWidth')) ) {
       breite = $('.search-bar-mobile').actual('innerWidth')  + 'px';
       breite2 = $('.search-bar-mobile').actual('innerWidth') - 50 + 'px';
       $('.search-results').css( "width",breite );
    }
  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 > 0 && 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();
     var  ajaxData = {
      "resources": {
          "type": 'product,collection',
          "limit": 6,
          "options": {
          "unavailable_products": 'last',
              "fields": 'title,product_type,variants.title,tag,vendor'
          }
      }
    };
      var url2 = '&resources[type]=product,collection'
      currentAjaxRequest = $.getJSON({
        'url':  "/search/suggest.json?q=" + term + url2,
        'type': 'GET',
        'dataType': 'json', // added data type
        data: ajaxData,
        'success': function(data) {
            //var productSuggestions = data.resources.results.products;
            //if (productSuggestions.length > 0) {
            //  var firstProductSuggestion = productSuggestions[0];
            //}
                    // Reset results.
          resultsList.empty();
          // If we have no results.
          if(data.resources.results.products.length == 0) {
            // resultsList.html('<li><span class="title">No results.</span></li>');
            // resultsList.fadeIn(200);
            resultsList.hide();
          } else {
            // If we have results.
            $.each(data.resources.results.products, function(index, item) {
              var link = $('<a></a>').attr('href', item.url);
              var bildurl = item.featured_image.url;
              if (bildurl !== null) {
                var Dateiendung =   bildurl.split('.').pop();
                var Bildklein =  bildurl.replace('.' + Dateiendung, '_thumb') + '.' + Dateiendung;
              } else {
                var Bildklein = '{{ 'no-image.png' | asset_img_url: '40x40' }}'
              }
              link.append('<span class="thumbnail"><img src="' + Bildklein  + '" /></span>');
              link.append('<span class="title" style="width:'+breite2+'">' + item.title + '</span>');
              link.wrap('<li class="pred-item"></li>');
              resultsList.append(link.parent());
            });
            if(data.resources.results.collections.length == 0) {
            } else {
            }
            $.each(data.resources.results.collections, function(index, item) {
              var link = $('<a></a>').attr('href', item.url);
              if (data.resources.results.collections[index].body == "") {
                link.append('<span class="Textstandard">'  + "alles zu " + '</span>');
                } else {
                link.append('<span class="Textstandard">'  + "alles von " + '</span>');
                }
              link.append('<span class="titleKat"  style="color:black">' + item.title + '</span>')
              link.append('<span class="Textstandard">'  + " anzeigen" + '</span>');
              link.wrap('<li class="pred-item pred-search-tit"></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>');
            }
            //Das Suchergebnis wird animiert über die Anzahl an ms eingeblendet
            resultsList.fadeIn(200);
          }
        }
      });
   }
     });
   });
 // Clicking outside makes the results disappear.
 $('body').bind('click', function(){
  $('.search-results').hide();
   });
});  
</script>

 

Highlighted
Shopify Partner
111 8 37

my website is https://www.menschenskinder-shop.de 

so you can check how it looks like.

Highlighted
Tourist
5 0 0

Hey,

Thank you so much for the code. I appreciate it a lot.

After making some minute changes to the code, it is working for me now.

Only issue is that See all results options is still not displaying in the resultsList.

If you know why it's behaving like that, please let me know.

Thanks a lot

0 Likes
Highlighted
Shopify Partner
111 8 37

Ah, yes, I also don't have this "see all results". I'll check as well, if you find out why it's not showing up, let me know

Highlighted
Shopify Partner
111 8 37

Rohan,

in my code you see

if(data.resources.results.collections.length == 0) {

with this you can run the see all results. Just copy this and replace data.results_count with it. Or better use products for the count

if(data.resources.results.products.length >5) {
0 Likes