Common implementation questions

Collection of frequently asked questions on the usage of our APIs. This is based on past conversations and issues we were able to help with our implementations.

Cannot read properties of undefined

If you encounter the following error:

Uncaught (in Promise) TypeError: Cannot read properties of undefined (reading 'General')
	at h.instrument (swym-ext-shopify.js?...om&v=3.95.0:261:357)
	at f.<computed> [as fetch] (swym-ext-shopify.js?....com&v=3.95.0:31:40)
	at eval (Wishlist.svelte:378:19)

This is mostly caused due to an incomplete implementation of our JS APIs. Here are some examples of improper API usage that could potentially throw this error:

Using window._swat to make the API calls might lead to timing issues where not all components of the Swym Storefront JS client have been fully loaded by the time the calls are made. This could explain why the xxxx.General being undefined when your code executes..

To avoid this, the best way is to use our JS APIs in a complete implementation by wrapping every extension with our fully loaded callback function. This ensures that your custom functions are queued in the window.SwymCallbacks array and executed after the Swym app has fully loaded. For detailed guidance on how to implement this, please refer to our help article on using the SwymCallback function.

// create a self-executing anonymous function to avoid leaking variables into the top level scope of window
(function() {
  // Executed after Swym Storefront JS Client has loaded all necessary resources.  
  function onSwymLoadCallback(swat) {  
    // Please make all Swym-related API calls inside this function.  
    // You can use the swat argument within this scope.  
  }  
  if (!window.SwymCallbacks) {  
    window.SwymCallbacks = [];  
  }  
  window.SwymCallbacks.push(onSwymLoadCallback);
})();

Queries regarding outdated API usage

Q1: Why am I receiving API errors?

As of May 24, 2024, the majority of the APIs listed in our older documentation (Swym API Reference ) are outdated. We strongly encourage all developers to transition to our latest API documentation available at Swym Developer Documentation, where the implementation of most API calls is explained in a more comprehensive manner.

Q2: What does outdated mean?

Outdated APIs are those that are no longer supported and will eventually be removed. Using outdated APIs can result in unexpected behaviour and implementation errors.

Q3: Are all the APIs in the old documentation outdated?

Not all APIs in the older documentation are outdated. However, the implementation of the majority of API calls has been explained in a more comprehensive manner in our latest developer documentation. For the best experience and support, we recommend using the latest documentation.

Q4: How can I migrate to the latest APIs?

Please refer to our latest API documentation at Swym Developer Documentation. This documentation provides comprehensive guides, examples, and best practices for implementing our current APIs.

Q5: What if I have already implemented APIs from the older documentation?

If you have already implemented APIs from our older documentation and need assistance transitioning to the latest APIs, please reach out to us at [email protected]. Our support team is available to help you identify the updated API calls and assist with the migration process.

Q6: What if I have questions during the migration process?

For any questions or concerns during the migration process, please contact our support team at [email protected]. We are here to help ensure a smooth transition to the latest API standards.

Social Count implementation on multiple products at once

Issue: Merchants face an issue when implementing the Fetch Wishlist Social Count API on collection pages. The API call is dependent only on the Product ID and not the Variant ID. Therefore, if there are multiple products with the same Product ID but different Variant IDs, the button will appear only once.

Solution: The script should be modified to handle multiple instances of the same Product ID correctly.

Step-by-Step Guide for Implementation Reference:

HTML Button Setup:

Add an HTML span with a similar structure to your collection page. This implementation works only when the EPI button is used. For more information on implementing this button, please refer to this article. For code readability, please place this span along with the EPI button enclosed within a

tag.

<span class="swym-collections-social-count swym-hide-social-count" onclick="event.target.parentElement.querySelector('#swym-collections').click()" data-product-id="{{ <product.id OR card_product.id based on what is used in your code> }}"></span>

JavaScript Code Implementation:

Include this script with a similar structure in your theme files. This script will handle fetching and displaying the social count for each product tile.

<script defer>
  (function() {
    function swymCallbackFn(swat) {
      // Step 1: Collect all product IDs from the buttons
      const productIdArray = [];
			const allSwymCollectionsButtons = document.querySelectorAll('.swym-collections-social-count');
			allSwymCollectionsButtons.forEach((button) => {
  		const productId = button.getAttribute('data-product-id');
  		if (productId) { // Only push if productId is not an empty string
    		productIdArray.push(productId);
  		}
			});
      // Step 2: Function to fetch social count for a given product ID
      function fetchSocialCount(productId) {
        return new Promise((resolve, reject) => {
          swat.wishlist.getSocialCount(
            { empi: productId },
            (data) => resolve({ productId, count: data }),
            (error) => reject({ productId, error })
          );
        });
      }
      // Step 3: Generate an array of promises for fetching social counts
      function generateFetchBody() {
        return productIdArray.map((productId) => fetchSocialCount(productId));
      }
      // Step 4: Execute all fetch requests simultaneously and update the buttons
      Promise.all(generateFetchBody())
        .then((results) => {
          console.log(results, 'results');
          results.forEach((result) => {
            // Find all buttons with the same product ID and update their counts
            const buttons = document.querySelectorAll(`.swym-collections-social-count[data-product-id="${result.productId}"]`);
            buttons.forEach((button) => {
              result.count.data.count ? (button.textContent = result.count.data.count) : (button.textContent = '');
              button.classList.remove('swym-hide-social-count');
            });
            console.log(result, 'result');
          });
        })
        .catch((error) => {
          console.error('Error fetching social counts:', error);
        });
      // Step 5: Update the social count when a product is added to the wishlist
      swat.evtLayer.addEventListener(swat.JSEvents.addedToWishlist, function(product) {
        let productId = product.detail.d.empi;
        let buttonsToUpdate = document.querySelectorAll(`.swym-collections-social-count[data-product-id="${productId}"]`);
        buttonsToUpdate.forEach((buttonToIncrease) => {
          let updatedNumber = Number(buttonToIncrease.textContent) + 1;
          buttonToIncrease.textContent = updatedNumber;
        });
      });
    }
    // Step 6: Ensure the callback function is registered
    if (!window.SwymCallbacks) {
      window.SwymCallbacks = [];
    }
    window.SwymCallbacks.push(swymCallbackFn);
  })();
</script>

A step-by-step Explanation for reference:

  1. Collect Product IDs:
    1. Gather all the collection buttons with a common distinct class swym-collections-social-count has been used in the above example.
    2. Extract and store their data-product-id attribute values in an array.
  2. Fetch Social Count:
    1. Define a function fetchSocialCount that takes a product ID and returns a promise.
    2. This promise resolves with the social count data for the product.
  3. Generate Fetch Requests:
    1. Create an array of promises using the product IDs by mapping each ID to a call to fetchSocialCount.
  4. Execute Fetch Requests:
    1. Use Promise.all to execute all fetch requests simultaneously.
    2. Update the corresponding buttons' text content with the retrieved social count.
    3. Ensure all buttons with the same product ID are updated.
  5. Update on Wishlist Addition:
    1. Add an event listener for the addedToWishlist event.
    2. When a product is added to the wishlist, update the social count for all corresponding buttons.

How to Implement a Custom "Save for Later" Button on Your Cart Page

Follow these steps to add a custom "Save for Later" button to your cart page. This feature allows customers to save items for later purchase. Note that this implementation is functional only on the cart pages. Please note that the Save for Later functionality must be enabled on the Swym Admin for this implementation to function correctly.

Step 1: Add the button HTML

Add the following HTML code to your desired location on the cart page:

<swym-sfl-line-button>
  <button
    id="swym-custom-sfl-btn"
    class="swym-sfl-line-button link"
    type="button"
    data-variant-id="{{ item.variant.id }}" // Insert tag that fetches the variant ID
    data-product-id="{{ item.product_id }}" // Insert tag that fetches the product ID
    data-product-url="{{ shop.url }}{{ item.url }}" // Insert tag that fetches the variant URL
    data-quantity="{{ item.quantity }}" // Insert tag that fetches the count to Save for later
    style="<Insert your custom styling here>"
  >
    Save For Later 
  </button>
</swym-sfl-line-button>

Step 2: Create and Add this Script to swym-custom.liquid

Create a file named swym-custom.liquid and add the following script:

<script>
(function() {
  function sflInit(swat) {
      swat.SaveForLater.init(
          sfl => {
              swat.sfl = sfl;
              swat.sflLid = sfl.listid;
              swat.SaveForLater.fetch(swat.sflLid, function(response){
                  swat.sfl.listcontents = response.items;
              }, err => console.error(err))
          },
          err => console.error(err)
      )
  }
  if (!window.SwymCallbacks) window.SwymCallbacks = [];
  window.SwymCallbacks.push(sflInit);
  class SwymSflLineButton extends HTMLElement {
      constructor() {
        super();
          this.button = this.querySelector('button');
          if(this.button) this.button.addEventListener('click', this._addToSFL.bind(this));
      }
      _addToSFL(evt){
        const product = [{
          'du': this.button.dataset.productUrl,
          'empi': this.button.dataset.productId,
          'epi': this.button.dataset.variantId,
          'qty': this.button.dataset.quantity
        }]
        const cartRemoveButton = this.button.closest('.cart-item').querySelector('cart-remove-button'); // Please modify these selectors according to your store
        _swat.SaveForLater.add(_swat.sflLid, product, res => console.log(res), err => console.error(err));
        cartRemoveButton.dispatchEvent(new CustomEvent('click'));
      }
    }
    customElements.define('swym-sfl-line-button', SwymSflLineButton);
})();
</script>

Step 3: Include the Script in theme.liquid

Add the following line to your theme.liquid file to include the script you created in Step 2:

{ % include 'swym-custom' %}

By following these steps, you can successfully add a "Save for Later" button to your cart page. If you have any further queries regarding this implementation, please reach out to [email protected] and we’ll be more than happy to assist you!

Additional Information

Once the code and script have been added, please add the appropriate CSS for the appearance of the social count.