Re: How to add Load more button on the collection page?

Solved

How to add Load more button on the collection page?

leechoostore
Excursionist
17 2 2

Hey, I need to add a "Load more" button below the collection page. I am using dawn theme. Can anyone help?

Thanks 🙂

Accepted Solutions (10)

BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

- Here is the solution for you @leechoostore 
- Please follow these steps: 

step.png

- Find the asset folder and add a new file "Ajaxinate.min.js" with the following content:

 

 

'use strict';

var Ajaxinate = function ajaxinateConstructor(config) {
  var settings = config || {};
  /*
    pagination: Selector of pagination container
    method: [options are 'scroll', 'click']
    container: Selector of repeating content
    offset: 0, offset the number of pixels before the bottom to start loading more on scroll
    loadingText: 'Loading', The text changed during loading
    callback: null, function to callback after a new page is loaded
  */
  var defaultSettings = {
    pagination: '#AjaxinatePagination',
    method: 'scroll',
    container: '#AjaxinateLoop',
    offset: 0,
    loadingText: 'Loading',
    callback: null
  };
  // Merge configs
  this.settings = Object.assign(defaultSettings, settings);

  // Bind 'this' to applicable prototype functions
  this.addScrollListeners = this.addScrollListeners.bind(this);
  this.addClickListener = this.addClickListener.bind(this);
  this.checkIfPaginationInView = this.checkIfPaginationInView.bind(this);
  this.stopMultipleClicks = this.stopMultipleClicks.bind(this);
  this.destroy = this.destroy.bind(this);

  // Set up our element selectors
  this.containerElement = document.querySelector(this.settings.container);
  this.paginationElement = document.querySelector(this.settings.pagination);

  this.initialize();
};

Ajaxinate.prototype.initialize = function initializeTheCorrectFunctionsBasedOnTheMethod() {
  // Find and initialise the correct function based on the method set in the config
  if (this.containerElement) {
    var initializers = {
      click: this.addClickListener,
      scroll: this.addScrollListeners
    };
    initializers[this.settings.method]();
  }
};

Ajaxinate.prototype.addScrollListeners = function addEventListenersForScrolling() {
  if (this.paginationElement) {
    document.addEventListener('scroll', this.checkIfPaginationInView);
    window.addEventListener('resize', this.checkIfPaginationInView);
    window.addEventListener('orientationchange', this.checkIfPaginationInView);
  }
};

Ajaxinate.prototype.addClickListener = function addEventListenerForClicking() {
  if (this.paginationElement) {
    this.nextPageLinkElement = this.paginationElement.querySelector('a');
    this.clickActive = true;
    if (this.nextPageLinkElement !== null) {
      this.nextPageLinkElement.addEventListener('click', this.stopMultipleClicks);
    }
  }
};

Ajaxinate.prototype.stopMultipleClicks = function handleClickEvent(event) {
  event.preventDefault();
  if (this.clickActive) {
    this.nextPageLinkElement.innerHTML = this.settings.loadingText;
    this.nextPageUrl = this.nextPageLinkElement.href;
    this.clickActive = false;
    this.loadMore();
  }
};

Ajaxinate.prototype.checkIfPaginationInView = function handleScrollEvent() {
  var top = this.paginationElement.getBoundingClientRect().top - this.settings.offset;
  var bottom = this.paginationElement.getBoundingClientRect().bottom + this.settings.offset;
  if (top <= window.innerHeight && bottom >= 0) {
    this.nextPageLinkElement = this.paginationElement.querySelector('a');
    this.removeScrollListener();
    if (this.nextPageLinkElement) {
      this.nextPageLinkElement.innerHTML = this.settings.loadingText;
      this.nextPageUrl = this.nextPageLinkElement.href;
      this.loadMore();
    }
  }
};

Ajaxinate.prototype.loadMore = function getTheHtmlOfTheNextPageWithAnAjaxRequest() {
  this.request = new XMLHttpRequest();
  this.request.onreadystatechange = function success() {
    if (this.request.readyState === 4 && this.request.status === 200) {
      var newContainer = this.request.responseXML.querySelectorAll(this.settings.container)[0];
      var newPagination = this.request.responseXML.querySelectorAll(this.settings.pagination)[0];
      this.containerElement.insertAdjacentHTML('beforeend', newContainer.innerHTML);
      this.paginationElement.innerHTML = newPagination.innerHTML;
      if (this.settings.callback && typeof this.settings.callback === 'function') {
        this.settings.callback(this.request.responseXML);
      }
      this.initialize();
    }
  }.bind(this);
  this.request.open('GET', this.nextPageUrl);
  this.request.responseType = 'document';
  this.request.send();
};

Ajaxinate.prototype.removeClickListener = function removeClickEventListener() {
  this.nextPageLinkElement.addEventListener('click', this.stopMultipleClicks);
};

Ajaxinate.prototype.removeScrollListener = function removeScrollEventListener() {
  document.removeEventListener('scroll', this.checkIfPaginationInView);
  window.removeEventListener('resize', this.checkIfPaginationInView);
  window.removeEventListener('orientationchange', this.checkIfPaginationInView);
};

Ajaxinate.prototype.destroy = function removeEventListenersAndReturnThis() {
  // This method is used to unbind event listeners from the DOM
  // This function is called manually to destroy "this" Ajaxinate instance
  var destroyers = {
    click: this.removeClickListener,
    scroll: this.removeScrollListener
  };
  destroyers[this.settings.method]();
  return this;
};

 

 

Then add the following code to the main-collection-product-grid.liquid

 

 

{{ 'ajaxinate.min.js' | asset_url | script_tag }}

 

 

Add the following code before {% schema %} in main-collection-product-grid.liquid

 

 

<script>
const endlessCollection = new Ajaxinate({
container: '#product-grid',
pagination: '.infinite_next',
});
</script>

 

 

- Find the file pagination.liquid:

Search for {%- if paginate.next -%} and add class="infinite_next" in <li>. So the code should look like below:

 

 

{%- if paginate.next -%}
          <li class="infinite_next">
            <a
              href="{{ paginate.next.url }}{{ anchor }}"
              class="pagination__item pagination__item--prev pagination__item-arrow link motion-reduce"
              aria-label="{{ 'general.pagination.next' | t }}"
            >
              {%- render 'icon-caret' -%}
            </a>
          </li>
        {%- endif -%}

 

 

- Adding code in facet.js File

- Search for static renderProductCount(html) and below that add the following code:

 

 

const endlessCollection = new Ajaxinate({
container: '#product-grid',
pagination: '.infinite_next',
});

 

 

- Adding code in component-pagination.css File

 

 

.pagination__list{
  display: none;
}

 

 

 

 

- Please press 'Like' and mark it as 'Solution' if you find it helpful. Thank you.

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now

View solution in original post

BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

The above code will help you automatically load more products on the collection page when customers scroll to the bottom of the page

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now

View solution in original post

BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

@leechoostore  if you want the "load more" button. follow the step

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now

View solution in original post

BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

- Add this code to theme.liquid

{% if template contains 'collection' %}
  <script src="{{ 'collection-load-more.js' | asset_url }}" defer="defer"></script>
{%endif%}

BSSTekLabs_0-1720873078620.png

 

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now

View solution in original post

BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

Add file collection-load-more.js in assest with content

 

const products_on_page = document.getElementById('product-grid');
const nextUrl = document.getElementById('paginateNext');
let next_url = nextUrl.dataset.nextUrl;

const load_more_btn = document.getElementsByClassName('load-more_btn')[0];
const load_more_spinner = document.getElementsByClassName('load-more_spinner')[0];
async function getNextPage() {
  try {
    let res = await fetch(next_url);
    return await res.text();
  } catch (error) {
    console.log(error);
  }
}

async function loadMoreProducts() {
  load_more_btn.style.display = 'none';
  load_more_spinner.style.display = 'block';
  let nextPage = await getNextPage();

  const parser = new DOMParser();
  const nextPageDoc = parser.parseFromString(nextPage, 'text/html');

  load_more_spinner.style.display = 'none';

  const productgrid = nextPageDoc.getElementById('product-grid');
  const new_products = productgrid.getElementsByClassName('grid__item');
  const newUrl = document.getElementById('paginateNext');
  const new_url = newUrl.dataset.nextUrl;
  if (new_url) {
    load_more_btn.style.display = 'flex';
  }
  next_url = new_url;
  for (let i = 0; i < new_products.length; i++) {
    products_on_page.appendChild(new_products[i]);
  }
}

 

BSSTekLabs_1-1720873182576.png

 

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now

View solution in original post

BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

- In the file main-collection-product-grid find {%- if paginate.pages > 1 -%}

and replace 

{%- if paginate.pages > 1 -%}
              {% render 'pagination', paginate: paginate, anchor: '' %}
{%- endif -%}

to 

            {%- if paginate.pages > 1 -%}
              <div class="load-more">
  <a class="load-more_btn text-center mt-12 button button--primary" onclick="loadMoreProducts()">Load More</a>
  <div class="load-more_spinner hidden w-8 h-8 ml-auto mr-auto border-4 border-solid border-black border-t-gray-200 rounded-full animate-spin"></div>
</div>
            {%- endif -%}

BSSTekLabs_2-1720873371984.png

 

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now

View solution in original post

BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

- Here is the result you will achieve:

BSSTekLabs_4-1720873825830.png

 

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now

View solution in original post

BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

Please try to follow my instructions @leechoostore 

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now

View solution in original post

leechoostore
Excursionist
17 2 2

This is an accepted solution.

This worked perfectly for infinite scroll! Thank you so much!

View solution in original post

leechoostore
Excursionist
17 2 2

This is an accepted solution.

This process worked perfectly for "Load more" button! Thanks a bunch!

View solution in original post

Replies 16 (16)

BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

- Here is the solution for you @leechoostore 
- Please follow these steps: 

step.png

- Find the asset folder and add a new file "Ajaxinate.min.js" with the following content:

 

 

'use strict';

var Ajaxinate = function ajaxinateConstructor(config) {
  var settings = config || {};
  /*
    pagination: Selector of pagination container
    method: [options are 'scroll', 'click']
    container: Selector of repeating content
    offset: 0, offset the number of pixels before the bottom to start loading more on scroll
    loadingText: 'Loading', The text changed during loading
    callback: null, function to callback after a new page is loaded
  */
  var defaultSettings = {
    pagination: '#AjaxinatePagination',
    method: 'scroll',
    container: '#AjaxinateLoop',
    offset: 0,
    loadingText: 'Loading',
    callback: null
  };
  // Merge configs
  this.settings = Object.assign(defaultSettings, settings);

  // Bind 'this' to applicable prototype functions
  this.addScrollListeners = this.addScrollListeners.bind(this);
  this.addClickListener = this.addClickListener.bind(this);
  this.checkIfPaginationInView = this.checkIfPaginationInView.bind(this);
  this.stopMultipleClicks = this.stopMultipleClicks.bind(this);
  this.destroy = this.destroy.bind(this);

  // Set up our element selectors
  this.containerElement = document.querySelector(this.settings.container);
  this.paginationElement = document.querySelector(this.settings.pagination);

  this.initialize();
};

Ajaxinate.prototype.initialize = function initializeTheCorrectFunctionsBasedOnTheMethod() {
  // Find and initialise the correct function based on the method set in the config
  if (this.containerElement) {
    var initializers = {
      click: this.addClickListener,
      scroll: this.addScrollListeners
    };
    initializers[this.settings.method]();
  }
};

Ajaxinate.prototype.addScrollListeners = function addEventListenersForScrolling() {
  if (this.paginationElement) {
    document.addEventListener('scroll', this.checkIfPaginationInView);
    window.addEventListener('resize', this.checkIfPaginationInView);
    window.addEventListener('orientationchange', this.checkIfPaginationInView);
  }
};

Ajaxinate.prototype.addClickListener = function addEventListenerForClicking() {
  if (this.paginationElement) {
    this.nextPageLinkElement = this.paginationElement.querySelector('a');
    this.clickActive = true;
    if (this.nextPageLinkElement !== null) {
      this.nextPageLinkElement.addEventListener('click', this.stopMultipleClicks);
    }
  }
};

Ajaxinate.prototype.stopMultipleClicks = function handleClickEvent(event) {
  event.preventDefault();
  if (this.clickActive) {
    this.nextPageLinkElement.innerHTML = this.settings.loadingText;
    this.nextPageUrl = this.nextPageLinkElement.href;
    this.clickActive = false;
    this.loadMore();
  }
};

Ajaxinate.prototype.checkIfPaginationInView = function handleScrollEvent() {
  var top = this.paginationElement.getBoundingClientRect().top - this.settings.offset;
  var bottom = this.paginationElement.getBoundingClientRect().bottom + this.settings.offset;
  if (top <= window.innerHeight && bottom >= 0) {
    this.nextPageLinkElement = this.paginationElement.querySelector('a');
    this.removeScrollListener();
    if (this.nextPageLinkElement) {
      this.nextPageLinkElement.innerHTML = this.settings.loadingText;
      this.nextPageUrl = this.nextPageLinkElement.href;
      this.loadMore();
    }
  }
};

Ajaxinate.prototype.loadMore = function getTheHtmlOfTheNextPageWithAnAjaxRequest() {
  this.request = new XMLHttpRequest();
  this.request.onreadystatechange = function success() {
    if (this.request.readyState === 4 && this.request.status === 200) {
      var newContainer = this.request.responseXML.querySelectorAll(this.settings.container)[0];
      var newPagination = this.request.responseXML.querySelectorAll(this.settings.pagination)[0];
      this.containerElement.insertAdjacentHTML('beforeend', newContainer.innerHTML);
      this.paginationElement.innerHTML = newPagination.innerHTML;
      if (this.settings.callback && typeof this.settings.callback === 'function') {
        this.settings.callback(this.request.responseXML);
      }
      this.initialize();
    }
  }.bind(this);
  this.request.open('GET', this.nextPageUrl);
  this.request.responseType = 'document';
  this.request.send();
};

Ajaxinate.prototype.removeClickListener = function removeClickEventListener() {
  this.nextPageLinkElement.addEventListener('click', this.stopMultipleClicks);
};

Ajaxinate.prototype.removeScrollListener = function removeScrollEventListener() {
  document.removeEventListener('scroll', this.checkIfPaginationInView);
  window.removeEventListener('resize', this.checkIfPaginationInView);
  window.removeEventListener('orientationchange', this.checkIfPaginationInView);
};

Ajaxinate.prototype.destroy = function removeEventListenersAndReturnThis() {
  // This method is used to unbind event listeners from the DOM
  // This function is called manually to destroy "this" Ajaxinate instance
  var destroyers = {
    click: this.removeClickListener,
    scroll: this.removeScrollListener
  };
  destroyers[this.settings.method]();
  return this;
};

 

 

Then add the following code to the main-collection-product-grid.liquid

 

 

{{ 'ajaxinate.min.js' | asset_url | script_tag }}

 

 

Add the following code before {% schema %} in main-collection-product-grid.liquid

 

 

<script>
const endlessCollection = new Ajaxinate({
container: '#product-grid',
pagination: '.infinite_next',
});
</script>

 

 

- Find the file pagination.liquid:

Search for {%- if paginate.next -%} and add class="infinite_next" in <li>. So the code should look like below:

 

 

{%- if paginate.next -%}
          <li class="infinite_next">
            <a
              href="{{ paginate.next.url }}{{ anchor }}"
              class="pagination__item pagination__item--prev pagination__item-arrow link motion-reduce"
              aria-label="{{ 'general.pagination.next' | t }}"
            >
              {%- render 'icon-caret' -%}
            </a>
          </li>
        {%- endif -%}

 

 

- Adding code in facet.js File

- Search for static renderProductCount(html) and below that add the following code:

 

 

const endlessCollection = new Ajaxinate({
container: '#product-grid',
pagination: '.infinite_next',
});

 

 

- Adding code in component-pagination.css File

 

 

.pagination__list{
  display: none;
}

 

 

 

 

- Please press 'Like' and mark it as 'Solution' if you find it helpful. Thank you.

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now
BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

The above code will help you automatically load more products on the collection page when customers scroll to the bottom of the page

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now
leechoostore
Excursionist
17 2 2

This is an accepted solution.

This worked perfectly for infinite scroll! Thank you so much!

NavigatePandabu
Visitor
2 0 0

life saver, thank you!

 

BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

@leechoostore  if you want the "load more" button. follow the step

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now
BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

- Add this code to theme.liquid

{% if template contains 'collection' %}
  <script src="{{ 'collection-load-more.js' | asset_url }}" defer="defer"></script>
{%endif%}

BSSTekLabs_0-1720873078620.png

 

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now
BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

Add file collection-load-more.js in assest with content

 

const products_on_page = document.getElementById('product-grid');
const nextUrl = document.getElementById('paginateNext');
let next_url = nextUrl.dataset.nextUrl;

const load_more_btn = document.getElementsByClassName('load-more_btn')[0];
const load_more_spinner = document.getElementsByClassName('load-more_spinner')[0];
async function getNextPage() {
  try {
    let res = await fetch(next_url);
    return await res.text();
  } catch (error) {
    console.log(error);
  }
}

async function loadMoreProducts() {
  load_more_btn.style.display = 'none';
  load_more_spinner.style.display = 'block';
  let nextPage = await getNextPage();

  const parser = new DOMParser();
  const nextPageDoc = parser.parseFromString(nextPage, 'text/html');

  load_more_spinner.style.display = 'none';

  const productgrid = nextPageDoc.getElementById('product-grid');
  const new_products = productgrid.getElementsByClassName('grid__item');
  const newUrl = document.getElementById('paginateNext');
  const new_url = newUrl.dataset.nextUrl;
  if (new_url) {
    load_more_btn.style.display = 'flex';
  }
  next_url = new_url;
  for (let i = 0; i < new_products.length; i++) {
    products_on_page.appendChild(new_products[i]);
  }
}

 

BSSTekLabs_1-1720873182576.png

 

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now
BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

- In the file main-collection-product-grid find {%- if paginate.pages > 1 -%}

and replace 

{%- if paginate.pages > 1 -%}
              {% render 'pagination', paginate: paginate, anchor: '' %}
{%- endif -%}

to 

            {%- if paginate.pages > 1 -%}
              <div class="load-more">
  <a class="load-more_btn text-center mt-12 button button--primary" onclick="loadMoreProducts()">Load More</a>
  <div class="load-more_spinner hidden w-8 h-8 ml-auto mr-auto border-4 border-solid border-black border-t-gray-200 rounded-full animate-spin"></div>
</div>
            {%- endif -%}

BSSTekLabs_2-1720873371984.png

 

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now
BSS-TekLabs
Shopify Partner
2401 695 830

- Add the code before div has id ProductGridContainer 

<div id="paginateNext" data-next-url="{{paginate.next.url}}" style="display: none">{{paginate.next.url}}</div>

like image

BSSTekLabs_3-1720873498093.png

 

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now
BSS-TekLabs
Shopify Partner
2401 695 830

Add this code to base.css

.load-more {
position: relative !important;
    justify-content: center !important;
    display: flex !important;
}

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now
BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

- Here is the result you will achieve:

BSSTekLabs_4-1720873825830.png

 

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now
BSS-TekLabs
Shopify Partner
2401 695 830

This is an accepted solution.

Please try to follow my instructions @leechoostore 

If our suggestions are useful, please let us know by giving it a like or marking it as a solution.


Salepify: Efficiently increase sales conversion with sale-driven features like auto add to cart, free gifts (free plan available)


Salemate: Boost your AVO with 2-layer offer, countdown upsell in your post purchase page


BSS Commerce - Full-service eCommerce Agency | Use Shopify for 1$ in the first month now
studiobalbis
Shopify Partner
7 1 2

This is great - really helpful, thank you.

 

I'm having a small issue which is the button is only loading half the number of items that the pagination is set to. I'm not a complete novice when it comes to javascript but I couldn't see anything in the code that would be causing that, and when I revert to the shopify built-in pagination with pages, the correct number of products loads per page.

 

Any ideas what could be causing this? I haven't edited your JS file, and my product grid liquid is below:

 

{{ 'template-collection.css' | asset_url | stylesheet_tag }}
{{ 'component-card.css' | asset_url | stylesheet_tag }}
{{ 'component-price.css' | asset_url | stylesheet_tag }}

{% if section.settings.image_shape == 'blob' %}
  {{ 'mask-blobs.css' | asset_url | stylesheet_tag }}
{%- endif -%}

{%- unless section.settings.quick_add == 'none' -%}
  {{ 'quick-add.css' | asset_url | stylesheet_tag }}
{%- endunless -%}

{{ 'custom__card.css' | asset_url | stylesheet_tag }}
{{ 'custom__collection.css' | asset_url | stylesheet_tag }}

{%- if section.settings.quick_add == 'standard' -%}
  <script src="{{ 'quick-add.js' | asset_url }}" defer="defer"></script>
  <script src="{{ 'product-form.js' | asset_url }}" defer="defer"></script>
{%- endif -%}

{%- if section.settings.quick_add == 'bulk' -%}
  <script src="{{ 'quick-add-bulk.js' | asset_url }}" defer="defer"></script>
  <script src="{{ 'quantity-popover.js' | asset_url }}" defer="defer"></script>
  <script src="{{ 'price-per-item.js' | asset_url }}" defer="defer"></script>
  <script src="{{ 'quick-order-list.js' | asset_url }}" defer="defer"></script>
{%- endif -%}

<script src="{{ 'product-grid-layout.js' | asset_url }}" defer="defer"></script>
<script src="{{ 'collection-load-more.js' | asset_url }}" defer="defer"></script>

{%- style -%}
  .section-{{ section.id }}-padding {
    padding-top: {{ section.settings.padding_top | times: 0.75 | round: 0 }}px;
    padding-bottom: {{ section.settings.padding_bottom | times: 0.75 | round: 0 }}px;
  }

  @media screen and (min-width: 750px) {
    .section-{{ section.id }}-padding {
      padding-top: {{ section.settings.padding_top }}px;
      padding-bottom: {{ section.settings.padding_bottom }}px;
    }
  }
{%- endstyle -%}

<div class="section-{{ section.id }}-padding gradient color-{{ section.settings.color_scheme }}">
  {%- paginate collection.products by section.settings.products_per_page -%}
    {% comment %} Sort is the first tabbable element when filter type is vertical {% endcomment %}
    {%- if section.settings.enable_sorting and section.settings.filter_type == 'vertical' -%}
      <facet-filters-form class="facets facets-vertical-sort page-width small-hide">
        <form class="facets-vertical-form" id="FacetSortForm">
          <div class="facet-filters sorting caption">
            <div class="facet-filters__field">
              <h2 class="facet-filters__label caption-large text-body">
                <label for="SortBy">{{ 'products.facets.sort_by_label' | t }}</label>
              </h2>
              <div class="select">
                {%- assign sort_by = collection.sort_by | default: collection.default_sort_by -%}
                <select
                  name="sort_by"
                  class="facet-filters__sort select__select caption-large"
                  id="SortBy"
                  aria-describedby="a11y-refresh-page-message"
                >
                  {%- for option in collection.sort_options -%}
                    <option
                      value="{{ option.value | escape }}"
                      {% if option.value == sort_by %}
                        selected="selected"
                      {% endif %}
                    >
                      {{ option.name | escape }}
                    </option>
                  {%- endfor -%}
                </select>
                <span class="svg-wrapper">
                  {{- 'icon-caret.svg' | inline_asset_content -}}
                </span>
              </div>
            </div>
          </div>
        </form>
      </facet-filters-form>
    {%- endif -%}

    <div class="{% if section.settings.filter_type == 'vertical' %} facets-vertical page-width{% endif %}">
      {{ 'component-facets.css' | asset_url | stylesheet_tag }}
      <script src="{{ 'facets.js' | asset_url }}" defer="defer"></script>
      {%- if section.settings.enable_filtering or section.settings.enable_sorting -%}
        <aside
          aria-labelledby="verticalTitle"
          class="facets-wrapper{% unless section.settings.enable_filtering %} facets-wrapper--no-filters{% endunless %}{% if section.settings.filter_type != 'vertical' %} page-width{% endif %}"
          id="main-collection-filters"
          data-id="{{ section.id }}"
        >
          <div class="collection-title-wrapper">
            <h2 class="collection-title h3">{{ collection.title }}</h2>
          </div>
          <div class="facet-description-wrapper">
            {% if section.settings.show_description %}
              <button
                class="facet-description body-font button-label small-hide"
                onclick="showDescription()"
                role="button"
              >
                Description
              </button>
            {% endif %}
            {% render 'facets',
              results: collection,
              enable_filtering: section.settings.enable_filtering,
              enable_sorting: section.settings.enable_sorting,
              filter_type: section.settings.filter_type,
              paginate: paginate
            %}
          </div>
        </aside>
        {% if section.settings.show_description %}
          <div id="collectionDescription" class="collection-description page-width">
            {{ collection.description }}
          </div>
        {% endif %}
      {%- endif -%}

      <div id="paginateNext" data-next-url="{{paginate.next.url}}" style="display: none">{{ paginate.next.url }}</div>
      <div
        class="product-grid-container{% if settings.animations_reveal_on_scroll %} scroll-trigger animate--slide-in{% endif %}"
        id="ProductGridContainer"
        {% if settings.animations_reveal_on_scroll %}
          data-cascade
        {% endif %}
      >
        {%- if collection.products.size == 0 -%}
          <div
            class="collection collection--empty {% if section.settings.margins %}page-width {% endif %}"
            id="product-grid"
            data-id="{{ section.id }}"
          >
            <div class="loading-overlay gradient"></div>
            <div class="title-wrapper center">
              <h2 class="title title--primary">
                {{ 'sections.collection_template.empty' | t -}}
                <br>
                {{
                  'sections.collection_template.use_fewer_filters_html'
                  | t: link: collection.url, class: 'underlined-link link'
                }}
              </h2>
            </div>
          </div>
        {%- else -%}
          <div
            class="collection{% if section.settings.filter_type != 'vertical' and section.settings.margins %} page-width{% endif %}"
          >
            <div class="loading-overlay gradient"></div>
            <div
              id="product-grid"
              data-id="{{ section.id }}"
              class="
                grid product-grid main-product-grid grid--{{ section.settings.columns_mobile }}-col-tablet-down grid--{{ section.settings.columns_desktop }}-col-desktop
                {% if section.settings.quick_add == 'bulk' %} collection-quick-add-bulk{% endif %}
              "
            >
              {% assign skip_card_product_styles = false %}
              {%- for product in collection.products -%}
                {% assign page_number = paginate.current_page | minus: 1 %}
                {% assign base_index = section.settings.products_per_page | times: page_number %}
                {% assign grid_index = base_index | plus: forloop.index %}
                {% assign lazy_load = false %}
                {%- if grid_index > 4 -%}
                  {%- assign lazy_load = true -%}
                {%- endif -%}
                {% for block in section.blocks %}
                  {% case block.type %}
                    {% when 'content' %}
                      {% if block.settings.index == grid_index %}
                        {% render 'grid-content-item',
                          span_horizontal: block.settings.horizontal_span,
                          span_vertical: block.settings.vertical_span,
                          forloop: forloop,
                          image: block.settings.image,
                          title: block.settings.title,
                          link: block.settings.link,
                          link_label: block.settings.link_label,
                          color_scheme: block.settings.color_scheme,
                          block_id: block.id
                        %}
                      {% endif %}
                  {% endcase %}
                {% endfor %}

                {% render 'grid-card-product',
                  forloop: forloop,
                  card_product: product,
                  media_aspect_ratio: section.settings.image_ratio,
                  image_shape: section.settings.image_shape,
                  show_secondary_image: section.settings.show_secondary_image,
                  show_vendor: section.settings.show_vendor,
                  show_rating: section.settings.show_rating,
                  lazy_load: lazy_load,
                  skip_styles: skip_card_product_styles,
                  quick_add: section.settings.quick_add,
                  section_id: section.id
                %}
                {%- assign skip_card_product_styles = true -%}
              {%- endfor -%}
            </div>

            {%- if paginate.pages > 1 -%}
              <div class="load-more">
                <a class="load-more_btn text-center mt-12 button button--primary" onclick="loadMoreProducts()"
                  >Load More</a
                >
                <div
                  class="load-more_spinner hidden w-8 h-8 ml-auto mr-auto border-4 border-solid border-black border-t-gray-200 rounded-full animate-spin"
                ></div>
              </div>
            {%- endif -%}
          </div>
        {%- endif -%}
      </div>
    </div>
  {%- endpaginate -%}
  {% if section.settings.image_shape == 'arch' %}
    {{ 'mask-arch.svg' | inline_asset_content }}
  {%- endif -%}
</div>
Dejan0515
Shopify Partner
1 0 0

I have also the same issue with you.

 let nextPage = await getNextPage();
This fetches the exact next page(page=2), but after parsing to DOM
( const nextPageDOM = parser.parseFromString(nextPage, 'text/html');), the log of nextPageDOM shows that it is page=1, and display the half number of page=2. Really weird and hope you help me out, thanks.
studiobalbis
Shopify Partner
7 1 2

I ended up using a different version of Ajaxinate that works for me. 

 

"use strict";

var Ajaxinate = function ajaxinateConstructor(config) {
  var settings = config || {};
  /*
    pagination: Selector of pagination container
    method: [options are 'scroll', 'click']
    container: Selector of repeating content
    offset: 0, offset the number of pixels before the bottom to start loading more on scroll
    loadingText: 'Loading', The text changed during loading
    callback: null, function to callback after a new page is loaded
  */
  var defaultSettings = {
    pagination: "#AjaxinatePagination",
    method: "scroll",
    container: "#AjaxinateLoop",
    offset: 0,
    loadingText: "Loading",
    callback: null,
  };
  // Merge configs
  this.settings = Object.assign(defaultSettings, settings);

  // Bind 'this' to applicable prototype functions
  this.addScrollListeners = this.addScrollListeners.bind(this);
  this.addClickListener = this.addClickListener.bind(this);
  this.checkIfPaginationInView = this.checkIfPaginationInView.bind(this);
  this.stopMultipleClicks = this.stopMultipleClicks.bind(this);
  this.destroy = this.destroy.bind(this);

  // Set up our element selectors
  this.containerElement = document.querySelector(this.settings.container);
  this.paginationElement = document.querySelector(this.settings.pagination);

  this.initialize();
};

Ajaxinate.prototype.initialize =
  function initializeTheCorrectFunctionsBasedOnTheMethod() {
    // Find and initialise the correct function based on the method set in the config
    if (this.containerElement) {
      var initializers = {
        click: this.addClickListener,
        scroll: this.addScrollListeners,
      };
      initializers[this.settings.method]();
    }
  };

Ajaxinate.prototype.addScrollListeners =
  function addEventListenersForScrolling() {
    if (this.paginationElement) {
      document.addEventListener("scroll", this.checkIfPaginationInView);
      window.addEventListener("resize", this.checkIfPaginationInView);
      window.addEventListener(
        "orientationchange",
        this.checkIfPaginationInView
      );
    }
  };

Ajaxinate.prototype.addClickListener = function addEventListenerForClicking() {
  if (this.paginationElement) {
    this.nextPageLinkElement = this.paginationElement.querySelector("a");
    this.clickActive = true;
    if (this.nextPageLinkElement !== null) {
      this.nextPageLinkElement.addEventListener(
        "click",
        this.stopMultipleClicks
      );
    }
  }
};

Ajaxinate.prototype.stopMultipleClicks = function handleClickEvent(event) {
  event.preventDefault();
  if (this.clickActive) {
    this.nextPageLinkElement.innerHTML = this.settings.loadingText;
    this.nextPageUrl = this.nextPageLinkElement.href;
    this.clickActive = false;
    this.loadMore();
  }
};

Ajaxinate.prototype.checkIfPaginationInView = function handleScrollEvent() {
  var top =
    this.paginationElement.getBoundingClientRect().top - this.settings.offset;
  var bottom =
    this.paginationElement.getBoundingClientRect().bottom +
    this.settings.offset;
  if (top <= window.innerHeight && bottom >= 0) {
    this.nextPageLinkElement = this.paginationElement.querySelector("a");
    this.removeScrollListener();
    if (this.nextPageLinkElement) {
      this.nextPageLinkElement.innerHTML = this.settings.loadingText;
      this.nextPageUrl = this.nextPageLinkElement.href;
      this.loadMore();
    }
  }
};

Ajaxinate.prototype.loadMore = function loadMore() {
  this.request = new XMLHttpRequest();

  this.request.onreadystatechange = function success() {
    if (!this.request.responseXML) {
      return;
    }
    if (!this.request.readyState === 4 || !this.request.status === 200) {
      return;
    }

    var newContainer = this.request.responseXML.querySelectorAll(
      this.settings.container
    )[0];
    var newPagination = this.request.responseXML.querySelectorAll(
      this.settings.pagination
    )[0];

    this.containerElement.insertAdjacentHTML(
      "beforeend",
      newContainer.innerHTML
    );

    if (typeof newPagination === "undefined") {
      this.removePaginationElement();
    } else {
      this.paginationElement.innerHTML = newPagination.innerHTML;

      if (
        this.settings.callback &&
        typeof this.settings.callback === "function"
      ) {
        this.settings.callback(this.request.responseXML);
      }

      this.initialize();
    }
  }.bind(this);

  this.request.open("GET", this.nextPageUrl);
  this.request.responseType = "document";
  this.request.send();
};

Ajaxinate.prototype.removeClickListener = function removeClickEventListener() {
  this.nextPageLinkElement.addEventListener("click", this.stopMultipleClicks);
};

Ajaxinate.prototype.removePaginationElement =
  function removePaginationElement() {
    this.paginationElement.innerHTML = "";
    this.destroy();
  };

Ajaxinate.prototype.removeScrollListener =
  function removeScrollEventListener() {
    document.removeEventListener("scroll", this.checkIfPaginationInView);
    window.removeEventListener("resize", this.checkIfPaginationInView);
    window.removeEventListener(
      "orientationchange",
      this.checkIfPaginationInView
    );
  };

Ajaxinate.prototype.destroy = function removeEventListenersAndReturnThis() {
  // This method is used to unbind event listeners from the DOM
  // This function is called manually to destroy "this" Ajaxinate instance
  var destroyers = {
    click: this.removeClickListener,
    scroll: this.removeScrollListener,
  };
  destroyers[this.settings.method]();
  return this;
};

 

It's also necessary to updates facets.js (assuming you're on Dawn or another base Shopify template) to refire the ajaxinate when facets are applied or disapplied. This is done by replacing this function in facets.js:

 

static renderProductGridContainer(html) {
    document.getElementById('ProductGridContainer').innerHTML = new DOMParser()
      .parseFromString(html, 'text/html')
      .getElementById('ProductGridContainer').innerHTML;

    document
      .getElementById('ProductGridContainer')
      .querySelectorAll('.scroll-trigger')
      .forEach((element) => {
        element.classList.add('scroll-trigger--cancel');
      });
  }

 

with this: 

 

static renderProductGridContainer(html) {
    document.getElementById("ProductGridContainer").innerHTML = new DOMParser()
      .parseFromString(html, "text/html")
      .getElementById("ProductGridContainer").innerHTML;

    document
      .getElementById("ProductGridContainer")
      .querySelectorAll(".scroll-trigger")
      .forEach((element) => {
        element.classList.add("scroll-trigger--cancel");
      });

    const endlessCollection = new Ajaxinate({
      container: "#product-grid",
      pagination: "#AjaxinatePagination",
      method: "click",
    });
  }

 

Obviously adjust the settings here as needed according to the Ajaxinate settings you want to use. 

 

Then on my main collection page I have this for the button:

 

{%- if paginate.next -%}
  <div id="AjaxinatePagination">
    <a href="{{ paginate.next.url }}" class="button button--primary paginate-button">Load More</a>
  </div>
{%- endif -%}

 

and this script at the bottom of the section:

 

<script>
  document.addEventListener("DOMContentLoaded", function() {
    const endlessCollection = new Ajaxinate({
      container: '#product-grid',
      pagination: '#AjaxinatePagination',
      method: "click"
    });
  });
</script>

 

(Again obviously adjust settings as needed). Hope that helps!

leechoostore
Excursionist
17 2 2

This is an accepted solution.

This process worked perfectly for "Load more" button! Thanks a bunch!