infiniteHits showMore() not working after upgrading to V 3.0.2

Hello everyone,

I have instantsearch with infiniteHits (algolia magento2 module ver. 3.0.2) implemented on Magento2 and It worked fine except for a Bug where clicking the “loadMore” button on the first results page would replace previous hits instead of loading more hits and appending them to the old ones, however the button worked as expected on the rest of result pages.

But after upgrading to algolia magento2 module ver. 3.1.0 and without making other code changes, the loadMore Button now only works on results page 1 with the behavior described above, and It stopped working on the rest of the result pages (where it used to behave correctly like infiniteHits should). I am also not getting any Javascript errors

  • vendor/algolia/algoliasearch-magento-2/view/frontend/web/instantsearch.js :
    (algolia module code, not modified)
  • vendor/company/custom-algolia/view/frontend/web/js/search.js:
    (used to customize few things from the algolia module)

    define(['jquery',
          'algoliaBundle',
          getTemplatesUrl,
          'mage/cookies',
          'jquery-ui-modules/effect',
          'jquery-ui-modules/effect-shake',
          ],
      function ($, algoliaBundle, templates,undefined1, undefined2) {
    
          // We load those via requirejs, as we want them browser cached and not included in every page
          $('body').append(templates)
    
    
          /** The widgets for these Attributes + price are always expanded, all others are collapsed.
           * @see algoliaBundle.instantsearch.setCollapsible
           */
          algoliaBundle.instantsearch.expandedAttributes = ["color", "size", "material", "length", "width", "height", "udropship_vendor"];
    
    
              /** Algolia widget to tweak search page
           * We add widgets (infinitescroll, infiniteHits)
           */
          algolia.registerHook('beforeInstantsearchStart', function (search) {
              const patchWidget = {
                  init: function (params) {
                      algoliaBundle.allHits = [];
                  },
    
                  render: function (params) {
                      jQuery(".ais-CurrentRefinements-item").each(function () {
                          if (jQuery(this).find('.ais-CurrentRefinements-label').text() == '3D-Ansicht:') {
                              jQuery(this).find('.current-refinement-name').text('Verfügbar');
                          }
                          if (jQuery(this).find('.ais-CurrentRefinements-label').text() == 'Typ:') { //type_id
                              jQuery(this).hide();
                          }
                          if (algoliaBundle.instantsearch.isVendorPage && jQuery(this).find('.ais-CurrentRefinements-label').text() == 'Hersteller:') { //udropship_vendor
                              jQuery(this).hide();
                          }
                      });
    
                      jQuery(".ais-HierarchicalMenu-link").click(function () {
                          jQuery('#algolia-static-content-desc').hide();
                      });
                      jQuery('.ais-InfiniteHits-loadMore').text("Mehr Produkte laden");
    
                      if(! jQuery('.ais-InfiniteHits-list').length) {
                          //no products found, need to add some structure first
                          jQuery('#instant-empty-results-container').remove();
                          jQuery('.ais-InfiniteHits').append('<ol class="ais-InfiniteHits-list"></ol>');
                      }
                      if(! jQuery(".ais-InfiniteHits-list #instant-hit-call-us").length) {
                          jQuery(jQuery.parseHTML(jQuery("#instant-hit-call-us-template-container").html())).appendTo(jQuery(".ais-InfiniteHits-list"));
                      }
                  }
    
              }
              const typer = {
                  init: function (options) {
                      algoliaBundle.instantsearch.updateType(options.state);
                  }
              }
    
              search.addWidgets([patchWidget, typer]);
    
              search.once('render', function () {
    
                  //jQuery('#current-refinements').next().append(jQuery('#rating'));
                  //also re-init popup help, to make sure click handler hits on hogan templates
                  if (window.algoliaConfig.attributeHelpMapping) {
                      window.algoliaConfig.attributeHelpMapping.forEach(function (elem) {
                          jQuery(".is-widget-container-" + elem + " .name").append('<div class="help-icon help-icon-blue" id="hilfe/attribute/' + elem + '"/>');
                      });
                      initPopupHelp();
                  }
    
              });
    
              algoliaBundle.allHits = [];
              return search;
          });
    
    
              /**
               * Adds a button to the page heading to hide (SEO) text of category or products description.
               * @param selector
               */
          algoliaBundle.instantsearch.addProductButton = function (selector) {
              if (jQuery('#product-toogle-button').length) {
                  return;
              }
              if(jQuery(selector).length && jQuery(selector).height() > 150) {
                  jQuery('.page-title-wrapper').append('<button class="button" id="product-toogle-button">Zu den Produkten</button>');
                  jQuery('#product-toogle-button').click(function () {
                      jQuery(selector).toggle("slow", function () {
                          if (jQuery('selector').is(":visible")) {
                              jQuery('#product-toogle-button').text("Zu den Produkten").attr("class", "button");
                          } else {
                              jQuery('#product-toogle-button').text("Beschreibung").attr("class", "button-light");
                          }
                      });
                  });
              }
          }
    
    
          /** Algolia provided Hook, used to flush persistet hits
           * @param search AlgoliaSearch Object
           * @returns search, appropriately modified
           */
          algolia.registerHook('afterInstantsearchStart', function (search) {
              search.helper.on('result', ({results: SearchResults, state: SearchParameters}) => {
                  //console.log("setting clearing hits flag")
                  algoliaBundle.clearHits = true;
              });
    
              search.helper.on('change', ({
                                              state: SearchParameters,
                                              results: SearchResults,
                                              isPageReset: boolean
                                          }) => {
                  algoliaBundle.instantsearch.updateType(SearchParameters);
              });
              return search;
          });
    
          algoliaBundle.instantsearch.getFilterCount = function(facets) {
              if (typeof facets === 'object') {
                  facets = Object.values(facets);
              }
              return facets.filter(el => {
                  if(typeof el  === 'object') {
                      return Object.keys(el).length > 0;
                  }
                  return el != null && el !== '';
              }).length;
          }
    
          algoliaBundle.instantsearch.updateType = function (state) {
              if (state.disjunctiveFacetsRefinements.hasOwnProperty('type_id')) {
                  delete state.disjunctiveFacetsRefinements.type_id;
              }
    
              var disjunctivelength = algoliaBundle.instantsearch.getFilterCount(state.disjunctiveFacetsRefinements);
              var cmsPage = $("[data-ui-id='page-title-wrapper']").html();
              algoliaBundle.instantsearch.isVendorPage = $("body").is(".umicrosite-index-landingpage");
              var umicrositeBeforeVendorProducts = $(".before-vendor-products");
              var umicrositeAfterVendorProducts = $(".after-vendor-products");
              if (
                  (disjunctivelength > 1 || (disjunctivelength == 1 && !("udropship_vendor" in state.disjunctiveFacetsRefinements)))
                  || algoliaBundle.instantsearch.getFilterCount(state.numericRefinements) > 1 //The 1 is the visibility facet
                  || algoliaBundle.instantsearch.getFilterCount(state.facetsRefinements) > 0
              ) {
                  state.disjunctiveFacetsRefinements["type_id"] = ["simple"];
              }
              if(algoliaBundle.instantsearch.isVendorPage) {
                  umicrositeBeforeVendorProducts.insertBefore(".algolia-instant-results-wrapper");
                  umicrositeAfterVendorProducts.insertAfter(".algolia-instant-results-wrapper");
                  state.disjunctiveFacetsRefinements["udropship_vendor"] = [cmsPage];
                  //algoliaBundle.instantsearch.addProductButton('.vendor-description');
              } else {
                  algoliaBundle.instantsearch.addProductButton('.category-description');
              }
          }
    
    
          /** Make a facet filter collapsible and callapse all facets except price
           * and algoliaBundle.instantsearch.expandedAttributes
           *
           */
          algoliaBundle.instantsearch.setCollapsed = function (entry) {
              if (entry.panelOptions) {
                  entry.panelOptions.collapsed = function (opts) {
                      var collapsed = !algoliaBundle.instantsearch.expandedAttributes.includes(entry.attribute);
                      if (entry.attribute.startsWith("price")) {
                          collapsed = false;
                      }
                      return collapsed;
                  }
              } else {
                  console.log(entry);
              }
          }
    
          /** Algolia provided Hook to tweak widget setup from instantsearch.js
           *  This will call setCollapsible on all facets, and remove unused widgets
           */
          algolia.registerHook('beforeWidgetInitialization', function(allWidgetConfiguration) {
    
              delete allWidgetConfiguration.hits;
    
              allWidgetConfiguration.rangeSlider.forEach(algoliaBundle.instantsearch.setCollapsed);
    
              allWidgetConfiguration.refinementList.forEach(algoliaBundle.instantsearch.setCollapsed);
    
              allWidgetConfiguration.rangeSlider.forEach(function (entry) {
                      if (entry.panelOptions) {
                          entry.panelOptions.hidden = function (opts) {
                              if (!opts.results
                                  || !opts.results._rawResults
                                  || !opts.results._rawResults[0].facets
                              ) return true;
                              if (opts.results._rawResults[0].facets_stats && opts.results._rawResults[0].facets_stats.hasOwnProperty(entry.attribute)) {
                                  const stat = opts.results._rawResults[0].facets_stats[entry.attribute];
                                  if (stat.min == stat.max) {
                                      return true;
                                  } else {
                                      return false;
                                  }
                              } else {
                                  return true;
                              }
                          }
                      }
                  }
              );
    
              allWidgetConfiguration.infiniteHits.transformItems = function (items) {
                  items.forEach(function (item) {
                      algoliaBundle.instantsearch.persistHit(item);
                  });
    
                  return items;
              };
    
              algoliaBundle.instantsearch.persistHit = function (hit) {
                  if (algoliaBundle.clearHits) {
                      algoliaBundle.clearHits = false;
                      algoliaBundle.allHits = [];
                      //		console.log("flushing hits");
                  }
                  //console.log("persiting: " + hit.name +" " + hit.objectID);
    
                  algoliaBundle.allHits.push(hit);
              }
    
              algoliaBundle.instantsearch.readOn = function () {
                  algoliaBundle.instantsearch.infiniteScrollAuto = false;
              }
    
              return allWidgetConfiguration;
          });
    
          return function() {
              return "company search";
          }
    });
    

My guess here is that the new module version broke the infiniteHits loadMore functionality, but still couldn’t figure out how and why, so any help would be much appreciated :slight_smile:

regards,
Mohamed

Hi! I looked in the changelog and in the source code of the extension for the the diff between 3.0.2 and 3.1.0:

Now I could not find any change related to infiniteHits in the magento2 extension. However, the js package for instantsearch provided by algoliaBundle was updated from v4.7.2 to v4.15.0

Looking at the changelog between these two instantsearch version, I could find these changes related to infiniteHits:

Could you maybe check that theses changes don’t collide with the specifics of your current implementation?

Looking forward to hear from you!

1 Like

Update: my GH links in the previous post are somehow not working.
Here are some hat will hopefully work:

1 Like

Thanks man! found the problem somewhere else in my code. The module turned out to be fine, however I still found a fix while reading the changelog :sweat_smile:
similarly to

I had to switch from:
helper.setQueryParameter
to
helper.state.setQueryParameter

1 Like