Elkfox / Ajaxinate

🎡 Ajax pagination plugin for Shopify themes

Home Page:https://ajaxinate.elkfox.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Issue with Ajax filters

josejk opened this issue · comments

When filters are applied and products are reloaded through Ajax the endless click will not work and will just take them to next page after that it works normal. This is a UX issue and would like to know if there is a solve for this. It can fixed by simply reloading the page after each Filter is added or removed but this will just make the site look poorly built.

@josejk Sounds like the pagination isn't being dynamically reloaded before you make the next request.

You'd need to modify the script to fetch the next page from your filtered request rather than the original paginated content.

Any suggestions on how to add that i have tried to do it through a callback and through an onLoad event.

As the next page is pulled from the URL in the pagination element you could update that element when you make your initial filtered Ajax request.

For those of you who are wrestling with this, here's what I ended up doing via a module, which isn't very refined – it uses window, it merely destroys and re-initializes – but which works

(The historicizeItemPage stuff isn't directly relevant to this issue, it was just a method I used to allow people who left a collection page which used infinite scroll to return to the 'page' of the item they clicked on, instead of returning to the very beginning of the collection. Products need a data attribute with the 'page' it's from for this to work)

import { Ajaxinate } from './ajaxinate.js';

/**
 * https://community.shopify.com/c/shopify-apps/code-splitting-modular-of-javascript-file-inside-theme-app/m-p/2062857/highlight/true#M63011
 * note we are importing the ESM file, not the dist package:
 * https://raw.githubusercontent.com/Elkfox/Ajaxinate/master/src/ajaxinate.js
 *
 * https://github.com/Elkfox/Ajaxinate
 * https://ajaxinate.elkfox.io
 */

const ajaxinateContainerSelector = '[data-ajaxinate]';
const ajaxinateNextPaginationLinkContainerSelector = '[data-ajaxinate-pagination-next]';
const itemPageSelector = '[data-itempage]';

/**
 * find what 'page' the item clicked is on, then push history so that when the user
 * returns to the collection, they are taken back to the same page
 * @param {Event} event
 */
function historicizeItemPage(event) {
  let url = new URL(location);
  const itemPageEl = event.target.closest(itemPageSelector);
  const page = itemPageEl.dataset.itempage;
  url.searchParams.set('page', page);
  window.history.scrollRestoration = 'manual';
  window.history.replaceState(null, '', url);
}

/**
 * initialize and add historicize listener (which we can do repeatedly without fear of
 * duplicating because they're the same function), either on page load or after filtering
 */
function ajaxinate() {
  const ajaxinateContainer = document.querySelector(ajaxinateContainerSelector);
  ajaxinateContainer.addEventListener('click', historicizeItemPage, { once: true });
  if (window?.ajaxination) window.ajaxination.destroy();
  window.ajaxination = new Ajaxinate({
    container: ajaxinateContainerSelector,
    pagination: ajaxinateNextPaginationLinkContainerSelector,
    method: 'scroll',
    offset: 300,
  });
}

/**
 * once collection filters have been applied, our original ajaxinate instance can't work, because
 * what it was targeting in the DOM has been destroyed and recreated – so we need to reinitialize,
 * and in order to know when to do that, we need to watch for changes filters make to the DOM
 */
function maybeWatchForFiltering() {
  /** FacetFiltersForm.renderProductCount() will change this element's innerHTML */
  const renderProductCountContainer = document.getElementById('ProductCount');
  if (renderProductCountContainer) {
    let observer = new window.MutationObserver(ajaxinate);
    observer.observe(renderProductCountContainer, { childList: true });
  }
}

/**
 * initialize when we have the necessary elements
 */
function maybeAjaxinate() {
  const ajaxinateContainer = document.querySelector(ajaxinateContainerSelector);
  const ajaxinateNextPaginationLinkContainer = document.querySelector(ajaxinateNextPaginationLinkContainerSelector);
  if (!ajaxinateContainer || !ajaxinateNextPaginationLinkContainer) return;
  ajaxinate();
  maybeWatchForFiltering();
}

document.addEventListener('DOMContentLoaded', maybeAjaxinate, { once: true });