Instantsearch.js: Custom <select> widget with multiple values

Created on 18 May 2017  路  4Comments  路  Source: algolia/instantsearch.js

Hello,

How can I make a custom widget that uses a <select> and can handle multiple values?
I have a custom widget that works with just 1 value and I now wanted to convert it into an widget that can handle multiple selections.

My current code:

instantsearch.widgets.customSelectorWidgetMultiple = function customSelectorWidgetMultiple(
  options
) {
  var container = options.container;
  var attributeName = options.attributeName;
  var limit = options.limit || 10;
  var title = options.title || 'All';
  var heading = options.heading;

  // container should be a CSS selector, so we convert it into a DOM element
  container = document.querySelector(container);
  // We'll internally keep track of the <select> element
  var selectElement = null;
  // We'll also need to keep track of the current selected value
  var currentlySelectedValue = [];

  return {
    // Method called at startup, to configure the Algolia settings
    getConfiguration: function getConfiguration() {
      // This is a copy-paste of the menu widget
      // We use a hierarchicalFacet and not a classical facet because we want to
      // keep the list of all possible values displayed at all times. With
      // a classical facet we would only have the list of possible values for
      // the current filters (which would not make any sense here)
      return {
        hierarchicalFacets: [
          {
            name: attributeName,
            attributes: [attributeName],
          },
        ],
      };
    },

    // Called on the first instantsearch search
    init: function init(options) {
      var helper = options.helper;
      var tooltip = '';

      if ($(container).attr('data-tooltip'))
        tooltip = getTemplate($(container).attr('data-tooltip'));
      // We add an (empty) <select> to the specified container
      container.innerHTML =
        '<div class="ais-header selectWidget"><label for="' +
        attributeName +
        '-select">' +
        heading +
        tooltip +
        '</label></div><div class="ais-body"><select id="' +
        attributeName +
        '-select" multiple data-maxOptions="1000"></select></div>';

      selectElement = container.querySelector('select');

      // We listen to the change event on that <select>
      selectElement.addEventListener('change', function() {
        // Finding the newly selected value
        var $selectElement = $(selectElement);

        helper.clearRefinements(attributeName);

        if (
          Array.isArray($selectElement.val()) &&
          $selectElement.val().length > 0
        ) {
          $selectElement.val().forEach(function(model) {
            console.log('SET: ' + attributeName + ' ' + model);
            helper.addDisjunctiveFacetRefinement(attributeName, model);
          });
        }

        helper.search();
      });

      $('#' + attributeName + '-select').selectpicker({
        liveSearch: true,
        noneSelectedText: 'Alles',
      });
    },

    // Called whenever we receive new results from Algolia
    render: function render(options) {
      var results = options.results;
      // We get the list of possible values for this search and sort them in the
      // same order everytime (most popular first)
      var sortBy = ['name:asc'];
      var facetValues = results.getFacetValues(attributeName, {
        sortBy: sortBy,
      }).data;
      var innerOptions = ['<option value="__EMPTY__">' + title + '</option>'];

      if (facetValues != null) {
        $(container).show();
        // We only keep the X first elements, as defined on instanciation
        facetValues = facetValues.slice(0, limit);

        // Then we add that to the <select>
        facetValues.forEach(function(facetValue) {
          // We mark the current one as selected
          var selected = facetValue.isRefined ? 'selected="selected"' : '';
          innerOptions.push(
            '<option value="' +
              facetValue.name +
              '" ' +
              selected +
              '>' +
              facetValue.name +
              '</option>'
          );
        });

        // Update the rendering
        selectElement.innerHTML = innerOptions.join('\n');
      } else {
        $(container).hide();
      }

      if (attributeName == 'beschrijving') {
        showHideModelArea();
      }

      $('#' + attributeName + '-select').selectpicker('refresh');
    },
  };
};

@vvo helped me with widget that accepts 1 value.

I get this error:
Uncaught Error: beschrijving is not defined in the disjunctiveFacets attribute of the helper configuration

I've tried multiple variations of facet settings in the getConfiguration part and in the search init part.

What am I doing wrong? Or is there already a (simple select and multi select) on Magento 1. I used @Maaark code as a starting point but then I got a different error than his : our facet is seemingly not "a retrieved facet".
I saw your response but I don't know how to make it work in our case.
Can you show me an example with a custom widget with the refinement list factory ?

Thanks

Here's an example: https://codesandbox.io/s/m51rloxwv9?module=%2Fsrc%2FrefinementSelect.js

It was indeed a bit harder than I expected, but this works

Thank you @Haroenv.

Was this page helpful?
0 / 5 - 0 ratings