Show more/previous replaces instead of appending in infiniteHits

Hi,
I have stumbled upon a weird behaviour in the infiniteHits widget. Before user action has changed the results in some way (search or facets changing), the click on “show more” replaces the hit content with page 2’s content and adds a “show previous” button. If the user first changes the search or filters some facet and then click on “show more”, it behaves as I expect and would like it to always behave. The new content is appended to the existing content and no “show previous” button. Can someone point me in the right direction what might be causing this?

Hi @fredrik.vestin

Sorry for the delayed reply due to the US holiday.

I haven’t heard of this particular behavior. Any chance you have it in a code sandbox or live site I can view?

Hi @chuck.meyer ,
I’m pretty tied up until the 8th of December but after that I can make an area where you can check it out. :slight_smile:

1 Like

Sounds good! Let’s pick it up then.

So, getting a little more time now, is there some way to send the details in private?

Sure – I’ll send you a DM now.

What are you using for your state cache? I notice routing information in the site as well – what are you using for routing?

The only active caching I know of is nginx cache and wprocket. And the routing is in the js-file.

  routing: {
    router: instantsearch.routers.history({
      windowTitle(routeState) {
        if (!routeState.s) {
          return mk_algolia_translations.searchPageTitleEmpty;
        }
        return mk_algolia_translations.searchPageTitle + routeState.s;
      },

      createURL({ qsModule, location, routeState }) {
        const { origin, pathname, hash } = location;
        const queryString = qsModule.stringify(routeState, { arrayFormat: "repeat" });

        // If completely empty search, set url to just ?s
        if (Object.values(routeState).every((el) => el === undefined)) {
          return `${origin}${pathname}?s${hash}`;
        }

        // Set empty s param before querystring if empty query
        if (!routeState.s) {
          return `${origin}${pathname}?s&${queryString}${hash}`;
        }

        return `${origin}${pathname}?${queryString}${hash}`;
      },

      parseURL({ qsModule, location }) {
        const {
          s = "",
          page,
          sortby,
          price,
          bladethickness,
          bladelength,
          netweight,
          brand = [],
          firesteelcompatible = [],
          category = [],
          gripmaterial = [],
          steeltype = [],
          childfriendly = [],
          serratededge = [],
          edgeprotection = [],
        } = qsModule.parse(location.search.slice(1));
        const allBrands = Array.isArray(brand) ? brand : [brand].filter(Boolean);
        const allFiresteelCompatible = Array.isArray(firesteelcompatible) ? firesteelcompatible : [firesteelcompatible].filter(Boolean);
        const allCategories = Array.isArray(category) ? category : [category].filter(Boolean);
        const allGripMaterials = Array.isArray(gripmaterial) ? gripmaterial : [gripmaterial].filter(Boolean);
        const allSteelTypes = Array.isArray(steeltype) ? steeltype : [steeltype].filter(Boolean);
        const allChildFriendly = Array.isArray(childfriendly) ? childfriendly : [childfriendly].filter(Boolean);
        const allSerratedEdge = Array.isArray(serratededge) ? serratededge : [serratededge].filter(Boolean);
        const allEdgeProtection = Array.isArray(edgeprotection) ? edgeprotection : [edgeprotection].filter(Boolean);

        return {
          s: decodeURIComponent(s),
          page,
          sortby,
          brand: allBrands.map(decodeURIComponent),
          category: allCategories.map(decodeURIComponent),
          steeltype: allSteelTypes.map(decodeURIComponent),
          firesteelcompatible: allFiresteelCompatible.map(decodeURIComponent),
          gripmaterial: allGripMaterials.map(decodeURIComponent),
          childfriendly: allChildFriendly.map(decodeURIComponent),
          serratededge: allSerratedEdge.map(decodeURIComponent),
          edgeprotection: allEdgeProtection.map(decodeURIComponent),
          price,
          bladelength,
          bladethickness,
          netweight,
        };
      },
    }),
    stateMapping: {
      stateToRoute(uiState) {
        const indexUiState = uiState[indexName] || {};

        return {
          s: indexUiState.query,
          page: indexUiState.page,
          sortby: indexUiState.sortBy,
          category: indexUiState.hierarchicalMenu && indexUiState.hierarchicalMenu["product_category_hierarchical.lvl0"],
          brand: indexUiState.refinementList && indexUiState.refinementList.brand,
          steeltype: indexUiState.refinementList && indexUiState.refinementList.steeltype,
          firesteelcompatible: indexUiState.refinementList && indexUiState.refinementList.firesteelcompatible,
          gripmaterial: indexUiState.refinementList && indexUiState.refinementList.gripmaterial,
          childfriendly: indexUiState.refinementList && indexUiState.refinementList.childfriendly,
          serratededge: indexUiState.refinementList && indexUiState.refinementList.serratededge,
          edgeprotection: indexUiState.refinementList && indexUiState.refinementList.edgeprotection,
          price: indexUiState.range && indexUiState.range["price." + mk_algolia_env.currency_zone + ".price"],
          bladelength: indexUiState.range && indexUiState.range.bladelength,
          bladethickness: indexUiState.range && indexUiState.range.bladethickness,
          netweight: indexUiState.range && indexUiState.range.netweight,
        };
      },

      routeToState(routeState) {
        const priceProperty = `price.${mk_algolia_env.currency_zone}.price`;

        let state = {
          products: {
            query: routeState.s,
            page: routeState.page,
            sortBy: routeState.sortby,
            refinementList: {
              brand: routeState.brand,
              steeltype: routeState.steeltype,
              firesteelcompatible: routeState.firesteelcompatible,
              gripmaterial: routeState.gripmaterial,
              childfriendly: routeState.childfriendly,
              serratededge: routeState.serratededge,
              edgeprotection: routeState.edgeprotection,
            },
            range: {
              [priceProperty]: routeState.price,
              bladelength: routeState.bladelength,
              bladethickness: routeState.bladethickness,
              netweight: routeState.netweight,
            },
          },
        };

        if (routeState.category.length > 0) {
          state.products.hierarchicalMenu = { "product_category_hierarchical.lvl0": routeState.category };
        }

        return state;
      },
    },
  },