How to add content to the query with autocomplete.js and instantsearch.js

To exclude some words from the search, it is possible to activate our advancedSyntax parameter, which allows you to add “-word” to get results which do not contain “word”.

If there are some words that you want to never see in the results, you could want to have those -myword added to every query sent to Algolia, but not displayed in your search boxes.

With autocomplete.js it’s easy.
For Shopify, I’ve described a bit how to change only the logic for products here: Filter by tag in autocomplete? .
Instead of params, you’ll want to change the source. The source code for the hits source is here , but basically, here’s what you want to do:

var oldSource = $.fn.autocomplete.sources.hits(params.index, {
  hitsPerPage: params.hitsPerPage,
  highlightPreTag: '<span class="aa-highlight">',
  highlightPostTag: '</span>'
});

var source = oldSource;

if (section === 'products') {
  source = function (query, cb) {
    query = '-ABC ' + query;
    return oldSource(query, cb);
  }
}

return {
  name: section,
  source: source,
  displayKey: 'title',
  templates: templates
}

With instantsearch.js, the only solution I see is a bit hackier. You can give a searchFunction when instantiating instantsearch.js. We’ll add it directly there.

  var oldState = null;

  var instant = {
    // ...
    search: instantsearch({
      appId: algolia.config.app_id,
      apiKey: algolia.config.search_api_key,
      indexName: '' + algolia.config.index_prefix + 'products',
      urlSync: {},
      searchFunction: function (opts) {
        var helper = instant.search.helper;
        var toAdd = '-ABC ';
        
        if (JSON.stringify(oldState) === JSON.stringify(helper.state)) return;
        oldState = helper.state;
        var oldQuery = helper.state.query;

        // Necessary just when reloading the page
        if (oldQuery.indexOf(toAdd) === 0) oldQuery = oldQuery.substring(toAdd.length);

        var newQuery;
        // This doesn't work with an empty query
        if (oldQuery === null || oldQuery === '' || oldQuery === toAdd) {
          newQuery = '';
        } else {
          newQuery = toAdd + oldQuery;
        }
        helper.setQuery(newQuery);
        opts.search();
        helper.setQuery(oldQuery);
      }
    }),
  };

This won’t prevent the text to be displayed in the URL. Unfortunately, we have no way to prevent this.

3 Likes

We have added this code in but it now when the user clicks on a facet refinement the refinement doesn’t happen. I removed one of the last lines, helper.setQuery(oldQuery); and this solves the issue however then the hidden exclusion word i.e. '-ABC ' now shows in the query input box.

Do you know any way to still hide this exclusion word and allow the user to still use all of the refinements?

P.S. the code you have written does hide the added query words from the URL

Many thanks in advanced!

Hi @matthew1 ! Could you share a link to your theme or to your store if this code is live?

Good catch!
The issue lied on the fact that to prevent an infinite loop, I was checking the query against the state query to see if it had changed. If it didn’t, I aborted.
To confirm this, select a few refinements, then add a space to your input on your store. You’ll see that they’re all suddenly applied.

The issue here is that selecting a refinement should trigger the search, but since the query was the same, we would abort anyway.

I’ve edited my previous post to instead compare the state entirely. This should work as intended.

1 Like

That’s really great - I had a feeling it was something to do with that - much appreciated, thanks!!

Just one little thing: you’ve missed out creating the oldState variable - just need to add var oldState = null; at the top of the instant search example

All the best, Matthew

1 Like

You’re right, thanks for the catch!
Edited to handle this correctly.

1 Like