How to implement dropdown filter and toggle

Hey Algolia peeps,

First a quick disclaimer, I’m a tech newbie. :grinning:

I’ve managed to get instantsearch.js to work on my project by following your tutorials. I would be grateful for any advice on how to implement the following features as I’m lost.

  1. I would like to add a dropdown filter similar in function and interface to the examples shown for Algolia Places.
  • I would like a user to only be able to search the cities and countries listed in my index.
  • This dropdown filter would need to be connected to instantsearch.js so a user can search for a product and select a location to further narrow down the displayed results.

I don’t know if I need to create seperate indexes for cities and countries to do this, or how to integrate the dropdown filter with instantsearch.js.

  1. I would like to add a simple toggle for the parameter highlight.
  • When the toggle is off it shows both highlight true and false results.
  • When it is on it shows only true results.

I’ve had a look at your documentation, but I can’t get this to work as I need to see a full example with the HTML included.

  1. I display all products on the homepage. I’ve successfully implemented search here. I also have several category and productTypes pages that are a
    subset of all products displayed on the homepage, such as “Electronics”, “Headphones”, “Laptops”. I would like to implement search on these pages as well.

I don’t know how to do this. I assume this will be the most difficult to implement.

  1. I’m worried about SEO. Is it best practice to include all products in noscript tags so if a user does not have javascript enabled they will still see the products, and search bots will be able to see the products that way as well?

  2. Is there a way to make the search URL more friendly? Right now, it looks like this: http://localhost:8000/?q=product&hPP=10&idx=index&p=0.

Is it possible to have: http://localhost:8000/?q=product

I know this is a lot so I’m grateful for any advice, code or examples you can provide. Everything I manage to put together comes from finding example code, copying it and playing around with to figure out how it all works. Below, I’ve attached my index and code. This is sample code and not my entire project as it makes things easier. I’m using Hugo, a static website builder for my website.

Thanks!

index.json

[{
"objectID": "1",
"cities": ["New York", "San Francisco"],
"company": "Apple",
"countries": ["United States"],
"description": "Best apples in the world",
"highlight": true,
"productTypes": ["Headphones", "Laptops"],
"category": "Electronics",
"title": "Apple Banana",
}]

index.html

    <!DOCTYPE html>
    <head>
    <link rel="stylesheet" href="/css/instantsearch.min.css">
    <link rel="stylesheet" href="/css/instantsearch-theme-algolia.min.css">
    </head>
    <body>
    <div class="" id="stats-container"></div>
    <div class=""><input id="search-input"></div>
    <div class="" id="hits"></div>
    <script src="/js/instantsearch.min.js"></script>
    <script src="/js/index.js"></script>
    </body>
    </html>

index.js

var search = instantsearch({
  appId: '',
  apiKey: '',
  indexName: 'index',
  urlSync: true,
  searchParameters: {
    hitsPerPage: 10
  }
});

search.addWidget(
  instantsearch.widgets.stats({
      container: '#stats-container',
      templates: {
          body: function(data) {
              return 'Browse ' + data.nbHits + ' Products'
          }
      }
  })
);

search.addWidget(
  instantsearch.widgets.searchBox({
    container: '#search-input',
    placeholder: 'Search',
    poweredBy: true
  })
);

var hitTemplate =
  '<div class="">' +
    '<h1 class="hit-company">{{company}}</h1>' +
    '<h2 class="hit-description">{{description}}</h2>' +
    '<h3 class="hit-title">{{title}}</h3>' +
    '<ul class="">' +
      '<li class="hit-locations">{{locations}}</li>' +
      '<li class="hit-category">{{category}}</li>' +
      '<li class="hit-productTypes">{{productTypes}}</li>' +
    '</ul>' +
  '</div>' 

var emptyTemplate = 
  '<article class="">' +
    '<p class="">Not found</p>' +
  '</article>'

search.addWidget(
  instantsearch.widgets.hits({
    container: '#hits',
    templates: {
      empty: emptyTemplate,
      item: hitTemplate
    },
    transformData: {
      item: function(hit) {
        hit.productTypes = hit.productTypes.join(', ');
        hit.locations = hit.locations.join(', ');
        return hit;
      }}
  })
);

search.start();

Hi @tommy,

I will try to respond to your answers with best that I can:

  1. For achieve such behaviour you can look at an other Algolia library called Autocomplete.js. You will be able to implement a dropdown like the one present in Places (it’s based on Autocomplete). But it’s your responsibility to sync the InstantSearch instance with the Autocomplete one. You can take a look at this issue as an example. You will need to create one index for both cities & countries, then you will target them with Autocomplete in order to find a correct location.

  2. For the toggle widget you should be able to have something that worked with (see below). It should return all the results by default and only the one that are highligted in the other case. Note that the attributeName should present in attributesForFaceting. You can find more informations about that in our documentation.

    instantsearch.widgets.toggle({
      container: '#toggle',
      attributeName: 'highlight',
      label: 'When checked only display "highlight" results',
    });
    
  3. For achieve such behaviour you will need to read find the correct category from the URL and then inject it in the InstantSearch instance with the searchParameters option. You can find more information about this parameter in our documentation. All the attributes pass to this option will be set as search parameters on the queries. For your example above it will be something like (see below). Note that we are working on a new API for the URL sync that will allow you to achieve such behaviour more easily. You can follow the progress on Github.

    // URL: http://localhost:8000/headphones
    
    const category = location.pathname.substr(1); // headphones
    
    const search = instantsearch({
      appId: '',
      apiKey: '',
      indexName: 'index',
      urlSync: true,
      searchParameters: {
        hitsPerPage: 10
        filters: 'productTypes:' + category
      }
    }};
    
  4. You’re not alone with this concern! We have a great FAQ article on SEO and Algolia which will provide you with some great insights. The noscript tag is not best practice, search engines are getting better at executing JS, a lot SEO people will argue you don’t need a fallback.

  5. You can choose which parameters you can track in the URL. For this you have an option on instantsearch called trackedParameters. You can find more informations about that in our documentation.

Hope that helps, let me know if you have questions :wink:

Thanks Samuel! :facepunch:

I’ll need a few days to take in what you have written and try it out.

I’ll get back to you if I have any difficulties.

Thanks again for taking the time to answer my questions. :pray: