algolia / autocomplete

🔮 Fast and full-featured autocomplete library
https://alg.li/autocomplete
MIT License
5.05k stars 331 forks source link

Show a single empty response when dealing with multiple indices #248

Closed AlphaGeek509 closed 6 years ago

AlphaGeek509 commented 6 years ago

Describe the bug 🐛 For each non-successful multi-index query; InstantSearch will return back the contents found inside the empty option from templates. This causes a very muddled user experience as they'll see this empty response even if a valid record is return from a queried index.

To Reproduce 🔍

//Search for BR6340-02-0.250 will yield a single record found.  However the empty string I've created will also be visible for all other indices where the query fails.

var client = algoliasearch('9G2RUKPPGE', '8860a74c330efaf0119818fcdd800126');

const indices = [
  ['SPR', 'Spacers'],
  ['SWG_SPR', 'Swage Spacers'],
  ['FF_STDF', 'Female-Female Standoffs'],
  ['SWG_STDF', 'Swage Standoffs'],
  ['MF_STDF', 'Male-Female Standoffs'],
  ['BSM', 'Ball Stud Males'],
  ['BSF', 'Ball Stud Females'],
  ['CHF', 'Chassis Fasteners'],
  ['MM_STDF', 'Male-Male Standoff'],
  ['SPR_TRQ', 'Super Torq Swage Standoffs'],
  ['CPS_1', 'Captive Panel Screw - Type 1']
];

const sources = indices.map(function(indexKeyValue) {
  var index = client.initIndex(indexKeyValue[0]);

  return {
    // source would be edited with the custom source from the other question
    source: $.fn.autocomplete.sources.hits(index, {
      hitsPerPage: 15,
    }),
    displayKey: 'code',
    templates: {
      suggestion: function(suggestion) {
        const markup = `
          <div class="row">
              <div class="col-xs-1 col-sm-1 col-md-1 nopadding">
                  <img src="${suggestion.image}" alt="" class="algolia-thumb">
              </div>
              <div class="col-xs-11 col-sm-11 col-md-11">
                  <div class="row">
                      <div class="col-xs-6 col-sm-8 col-md-8">
                          <span>${suggestion._highlightResult.code.value}</span>
                      </div>
                      <div class="col-xs-6 col-sm-4 col-md-4">
                          <span>Available Qty: ${suggestion.quantityAvailable.toLocaleString()}</span>
                      </div>
                  </div>
                  <div class="row hidden-xs">
                      <div class="col-sm-12 col-md-12 col-lg-12 col-xl-12">
                          <span>${suggestion.description}</span>
                      </div>
                  </div>
              </div>
          </div>`;

        return `<div class="algolia-result">${markup}</div>`;
      },
      empty: function(options) {
        return `<div class="algolia-result"><span> No results were found with your current selection.</span></div>`;
      },
    },
  };
});

$('#aa-search-input').autocomplete({
    hint: true,
    debug: true
  },
  sources
).on('autocomplete:selected', function(event, suggestion, dataset) {
  window.location.href = window.location.origin + '/' + suggestion.url
});

I've created a JSFiddle that can be ran by going here

Expected behavior 💭 I expect not to see any empty div message when at least one dataset has valid results. Only show the empty message when all datasets are empty.

Screenshots 🖥 screen shot 2018-08-23 at 10 46 05 am

Environment: This issue is visible on any platform.

Additional context It makes me wonder if the empty option can be established outside of the templates portion and applied in a more "global" fashion.

AlphaGeek509 commented 6 years ago

I discovered that the empty template can be set in a "global" fashion via Algolia.

//Search for BR6340-02-0.250 > Success
//Search for blah > Failure

var client = algoliasearch('9G2RUKPPGE', '8860a74c330efaf0119818fcdd800126');

const indices = [
  ['SPR', 'Spacers'],
  ['SWG_SPR', 'Swage Spacers'],
  ['FF_STDF', 'Female-Female Standoffs'],
  ['SWG_STDF', 'Swage Standoffs'],
  ['MF_STDF', 'Male-Female Standoffs'],
  ['BSM', 'Ball Stud Males'],
  ['BSF', 'Ball Stud Females'],
  ['CHF', 'Chassis Fasteners'],
  ['MM_STDF', 'Male-Male Standoff'],
  ['SPR_TRQ', 'Super Torq Swage Standoffs'],
  ['CPS_1', 'Captive Panel Screw - Type 1']
];

const sources = indices.map(function(indexKeyValue) {
  var index = client.initIndex(indexKeyValue[0]);

  return {
    // source would be edited with the custom source from the other question
    source: $.fn.autocomplete.sources.hits(index, {
      hitsPerPage: 15,
    }),
    displayKey: 'code',
    templates: {
      suggestion: function(suggestion) {
        const markup = `
          <div class="row">
              <div class="col-xs-1 col-sm-1 col-md-1 nopadding">
                  <img src="${suggestion.image}" alt="" class="algolia-thumb">
              </div>
              <div class="col-xs-11 col-sm-11 col-md-11">
                  <div class="row">
                      <div class="col-xs-6 col-sm-8 col-md-8">
                          <span>${suggestion._highlightResult.code.value}</span>
                      </div>
                      <div class="col-xs-6 col-sm-4 col-md-4">
                          <span>Available Qty: ${suggestion.quantityAvailable.toLocaleString()}</span>
                      </div>
                  </div>
                  <div class="row hidden-xs">
                      <div class="col-sm-12 col-md-12 col-lg-12 col-xl-12">
                          <span>${suggestion.description}</span>
                      </div>
                  </div>
              </div>
          </div>`;

        return `<div class="algolia-result">${markup}</div>`;
      }
    }
  };
});

$('#aa-search-input').autocomplete({
    hint: true,
    debug: true,
    templates: {
         empty: `<div class="algolia-result"><span> No results were found with your current selection.</span></div>`
    }
  },
  sources
).on('autocomplete:selected', function(event, suggestion, dataset) {
  window.location.href = window.location.origin + '/' + suggestion.url
});

I've got a couple things going on here that are cool.

  1. I am iterating over an array that holds the names of the indices that I want to query against. This was able to dramatically cut down on the redundant code that I was going to write based off of Algolia's tutorials.
  2. I discovered, in more research, that I could have a "default template" in the root autocomplete() function as an option. With that default template it was as simple as adding an 'empty' option to it. This option checks to see if all the datasets are empty, then in my case, display a simple div.

Credit to these authors for getting me to the solution.

A functioning fiddle can be found here: http://jsfiddle.net/jandk4014/rtkhw7o0/43/