Button initialisation for infinte/dynamic page load

Created by Subham Choudhury, Modified on Sat, 22 Jun at 4:33 PM by Subham Choudhury

TABLE OF CONTENTS


The EPI button code on the collections exists on the product cards in the collections but they simply don’t show up when filters are applied / dynamic sections. 


Ever wondered why? - That’s because the EPI button was not initialized! 


Why should the button be initialized?

The button needs to be initialized to ensure it is loaded and ready for use before clicking. In dynamically rendered sections such as filters, an infinite scroll that re-renders collection tiles, and Quickview modals, the buttons needs to be initialized before they can be used. 


The initialization process ensures that the necessary attributes are loaded and available for the button to function correctly. The button may not work correctly without proper initialization, leading to errors or unexpected behavior.


Note: Button initialization is only required on the dynamic sections of the collections page. For instance, if the entire page reloads after applying filters, the buttons are automatically initialized during the load as the product cards' markup are built.


What are Custom Events in Javascript?

(This section is only meant for the logic explanation and can be skipped)

In JavaScript, custom events allow developers to create and dispatch their own events, which can be detected and handled by other parts of the application. Custom events enable the decoupling of various components of an application, making the code more modular, reusable, and easier to maintain.


To create a custom event, you need to use the CustomEvent constructor, which takes two arguments - the event name and an optional object that specifies additional properties for the event. Once the custom event is created, you can dispatch it using the dispatchEvent method, passing in the custom event object as an argument.


Here's an example of how to create and use a custom event in JavaScript:


// Create a custom event
const customEvent = new CustomEvent('customEvent', {
  detail: {
    message: 'Hello from the custom event!'
  }
});
// Dispatch the custom event on a button click
const button = document.querySelector('button');
button.addEventListener('click', function() {
  button.dispatchEvent(customEvent);
});
// Handle the custom event
const output = document.querySelector('.output');
document.addEventListener('customEvent', function(event) {
  output.textContent = event.detail.message;
});

In this example, we create a custom event called 'customEvent' with a message payload of 'Hello from the custom event!'. We then dispatch the event when the user clicks on a button.


Finally, we handle the custom event by listening to it on the document object and updating the content of a DOM element with the message payload.


When the user clicks on the button, the custom event is dispatched, and the event listener is triggered, updating the content of the output element with the custom message.


How we can initialize the EPI button on collections?

Pre-requisite: The EPI button can only be initialised when all the attributes such as data-variant-id, data-product-url & data-product-id are present and valid as present in our collections article.



Step 1: Determine where we need to initialise the button (infinite load, collections, quickview)






In this example, we’d have to initialize the button on the filters

The button code is actually present here, but it is not initialized to be shown on the store-front




How to differentiate between an initialised button and un-initialised button?

swym-loaded class helps us to differentiate between initialised button and un-initialised button. To elaborate, an un-initialised button wouldn’t have the above swym-loaded class in its ClassList!


Step 2: Check for network calls that get triggered when filters are applied


Open the developers tool (⌘⌥I) > Network > Apply Fetch/XHR filter > Now apply filters on the collections to record the network calls > Choose a network call > Open the Initiator tab and go through the call stack



While going through the callstack, ignore any swym network calls and other uglified files!






For this store, whenever filters are being applied the products are dynamically re-loaded using the renderSectionFromFetch function in the facets.js file. Thus, we have to dispatch a custom event to initialize our buttons!


Here’s the code to dispatch our custom event:


document.dispatchEvent(new CustomEvent("swym:collections-loaded"));


Note: The custom event doesn’t have to be “swym:collections-loaded”. It can be named anything but make sure to listen to the same!



If you are not sure if a particular functions gets triggered when filters are applied, just add console logs and analyse the console when filters are applied



Step 3: Dispatch the custom event


It is advised to dispatch the custom event at the end of the function so that the theme functionality is not hindered, like this:



static renderSectionFromFetch(url, event) {
    fetch(url)
      .then(response => response.text())
      .then((responseText) => {
        const html = responseText;
        FacetFiltersForm.filterData = [...FacetFiltersForm.filterData, { html, url }];
        FacetFiltersForm.renderFilters(html, event);
        FacetFiltersForm.renderProductGridContainer(html);
        FacetFiltersForm.renderProductCount(html);
      });
    // Swym code starts here  
    document.dispatchEvent(new CustomEvent("swym:collections-loaded"));
    // Swym code ends here
  }

 


Step 4: Listen to our custom event by creating a custom file


Create a swym-custom.liquid file inside the Snippets sections and the following code snippet


<script defer>
  function swymCallbackFn(swat){
    document.addEventListener("swym:collections-loaded", function(){
      swat.initializeActionButtons("<<Collections Grid PARENT Selector>>");
    });
  }
  if(!window.SwymCallbacks){
    window.SwymCallbacks = [];
  }
  window.SwymCallbacks.push(swymCallbackFn);
</script>


When a script tag includes the defer attribute, it tells the browser to defer the execution of the script until the HTML content has been fully loaded and parsed.


Step 5: Include the swym-custom file inside the theme.liquid


Please use the below code snippet to include the swym-custom file in theme.liquid


{% include 'swym-custom' %}

So now the EPI button should work on filters, right?


There might be some cases where our custom event was triggered even before the dynamic sections have loaded. In these cases, we need to delay the execution of our custom event. We can achieve this using setTimeout function in Javascript


What is setTimeout?


setTimeout is a built-in JavaScript function that allows you to schedule the execution of a specified piece of code after a certain delay. It takes two arguments: a function to execute, and a delay time in milliseconds.


The general syntax for using setTimeout is as follows:


setTimeout(function, delay);


Step 6: Implementing a setTimeout


As mentioned in the above section, we would have to declare a function expression with our custom event in its body! For this example, it would look as follows:


<script defer>
  function swymCallbackFn(swat){
    document.addEventListener("swym:collections-loaded", function(){
      setTimeout( () => { 
      swat.initializeActionButtons("body");
      },1500);
    })
  }
  if(!window.SwymCallbacks){
    window.SwymCallbacks = [];
  }
  window.SwymCallbacks.push(swymCallbackFn);
</script>


Ta-da! Now the EPI button would work as expected even on the filters!


 


Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article