Solved

Selecting variants by clicking their images - craft theme

Vaseformyplace
Visitor
3 0 0

Hi everyone, I am stuck! I have tried to add this code into my theme (using Craft) and it won’t properly work. I am unsure what to do next. I tried to use the code in both theme.liquid and theme-editor.js 

Both are not taking the code and I am still unable to get the correct variant selected when on the correlating photo. 

const selectVariantByClickingImage = {
  // Create variant images from productJson object
  _createVariantImage: function (product) {
    const variantImageObject = {};
    product.variants.forEach((variant) => {
      if (
        typeof variant.featured_image !== 'undefined' &&
        variant.featured_image !== null
      ) {
        const variantImage = variant.featured_image.src
          .split('?')[0]
          .replace(/http(s)?:/, '');
        variantImageObject[variantImage] =
          variantImageObject[variantImage] || {};
        product.options.forEach((option, index) => {
          const optionValue = variant.options[index];
          const optionKey = `option-${index}`;
          if (
            typeof variantImageObject[variantImage][optionKey] === 'undefined'
          ) {
            variantImageObject[variantImage][optionKey] = optionValue;
          } else {
            const oldValue = variantImageObject[variantImage][optionKey];
            if (oldValue !== null && oldValue !== optionValue) {
              variantImageObject[variantImage][optionKey] = null;
            }
          }
        });
      }
    });
    return variantImageObject;
  },
  _updateVariant: function (event, id, product, variantImages) {
    const arrImage = event.target.src
      .split('?')[0]
      .replace(/http(s)?:/, '')
      .split('.');
    const strExtention = arrImage.pop();
    const strRemaining = arrImage.pop().replace(/_[a-zA-Z0-9@]+$/, '');
    const strNewImage = `${arrImage.join('.')}.${strRemaining}.${strExtention}`;
    if (typeof variantImages[strNewImage] !== 'undefined') {
      product.variants.forEach((option, index) => {
        const optionValue = variantImages[strNewImage][`option-${index}`];
        if (optionValue !== null && optionValue !== undefined) {
          const selects = document.querySelectorAll('#'+ id + ' [class*=single-option-selector]');
          const options = selects[index].options;
          for (let option, n = 0; (option = options[n]); n += 1) {
            if (option.value === optionValue) {
              selects[index].selectedIndex = n;
              selects[index].dispatchEvent(new Event('change'));
              break;
            }
          }
        }
      });
    }
  },
  _selectVariant: function() {
    const productJson = document.querySelectorAll('[id^=ProductJson-');
    if (productJson.length > 0) {
      productJson.forEach((product) => {
        const sectionId = product.id.replace("ProductJson-", "shopify-section-");
        const thumbnails = document.querySelectorAll('#'+ sectionId + ' img[src*="/products/"]');
        if (thumbnails.length > 1) {
          const productObject = JSON.parse(product.innerHTML);
          const variantImages = this._createVariantImage(productObject);
          // need to check variants > 1
          if (productObject.variants.length > 1) {
            thumbnails.forEach((thumbnail) => {
              thumbnail.addEventListener('click', (e) =>
                this._updateVariant(e, sectionId, productObject, variantImages),
              );
            });
          }
        }
      });
    }
  },
};
if (document.readyState !== 'loading') {
  selectVariantByClickingImage._selectVariant();
} else {
  document.addEventListener(
    'DOMContentLoaded',
    selectVariantByClickingImage._selectVariant(),
  );
}
Accepted Solution (1)
layoutbase
Pathfinder
111 13 24

This is an accepted solution.

Hi @Vaseformyplace,

 

Seems like there are some errors in the code. Try implementing these fixes by following the steps below:

  1. Go to Shopify Theme Editor > Edit Code
  2. Update the code below in theme-editor.js

 

const selectVariantByClickingImage = {
  // Create variant images from productJson object
  _createVariantImage: function (product) {
    const variantImageObject = {};
    product.variants.forEach((variant) => {
      if (typeof variant.featured_image !== 'undefined' && variant.featured_image !== null) {
        const variantImage = variant.featured_image.src
          .split('?')[0]
          .replace(/http(s)?:/, '');
        variantImageObject[variantImage] = variantImageObject[variantImage] || {};
        product.options.forEach((option, index) => {
          const optionValue = variant.options[index];
          const optionKey = `option-${index}`;
          if (typeof variantImageObject[variantImage][optionKey] === 'undefined') {
            variantImageObject[variantImage][optionKey] = optionValue;
          } else {
            const oldValue = variantImageObject[variantImage][optionKey];
            if (oldValue !== null && oldValue !== optionValue) {
              variantImageObject[variantImage][optionKey] = optionValue;
            }
          }
        });
      }
    });
    return variantImageObject;
  },
  _updateVariant: function (event, id, product, variantImages) {
    const arrImage = event.src
      .split('?')[0]
      .replace(/http(s)?:/, '')
      .split('.');
    const strExtention = arrImage.pop();
    const strRemaining = arrImage.pop();
    const strNewImage = `${arrImage.join('.')}.${strRemaining}.${strExtention}`;
    
    if (typeof variantImages[strNewImage] !== 'undefined') {
      product.variants.forEach((option, index) => {
        const optionValue = variantImages[strNewImage][`option-${index}`];
        if (optionValue !== null && optionValue !== undefined) {
          const selects = document.querySelectorAll('#'+ id + ' [class*=select__select]');
          const options = selects[index].options;
          for (let option, n = 0; (option = options[n]); n += 1) {
            if (option.value === optionValue) {
              selects[index].selectedIndex = n;
              selects[index].dispatchEvent(new Event('change'));
              break;
            }
          }
        }
      });
    }
  },
  _selectVariant: function() {
    const productJson = document.querySelectorAll('[id^=ProductJson-');
    if (productJson.length > 0) {
      productJson.forEach((product) => {
        const sectionId = product.id.replace("ProductJson-", "MainProduct-");
        const thumbnails = document.querySelectorAll('#'+ sectionId + ' .thumbnail img');
        if (thumbnails.length > 1) {
          const productObject = JSON.parse(product.innerHTML);
          const variantImages = this._createVariantImage(productObject);
          var _this = this;
          document.addEventListener('click', function(e) {
              e = e || window.event;
              var target = e.target;
            if(target.classList.contains('thumbnail')){
              _this._updateVariant(target.querySelector('img'), sectionId, productObject, variantImages)
            }
          }, false);
        }
      });
    }
  },
};
if (document.readyState !== 'loading') {
  selectVariantByClickingImage._selectVariant();
} else {
  document.addEventListener(
    'DOMContentLoaded',
    selectVariantByClickingImage._selectVariant(),
  );
}

 

  • Add this code before </head> in theme.liquid:

 

<script src="{{ 'theme-editor.js' | asset_url }}" defer="defer"></script>​

 

  • Add this code in the section: sections/main-product.liquid

 

{% unless product == empty %}
  <script type="application/json" id="ProductJson-{{ section.id }}">
    {{ product | json }}
  </script>
{% endunless %}
​

 

This should integrate the required feature into your thumbnail layout. Let us know if this works for you. If you find this suggestion helpful, please consider liking us and accepting this as the solution. Happy building 🔨😀

Please let us know if you find it helpful by giving us a LIKE and Mark as Solution. Layoutbase is a leading Shopify page builder. Give us a try!

View solution in original post

Replies 10 (10)

layoutbase
Pathfinder
111 13 24

Hi there, this is Layoutbase - Homepage & Blog Page Builder.  Seems like we can provide a quick fix! Would you kindly provide the URL to your store?

Please let us know if you find it helpful by giving us a LIKE and Mark as Solution. Layoutbase is a leading Shopify page builder. Give us a try!
Vaseformyplace
Visitor
3 0 0

Hi! Link here:

https://vase-for-my-place.myshopify.com/

Password: chaida 

layoutbase
Pathfinder
111 13 24

This is an accepted solution.

Hi @Vaseformyplace,

 

Seems like there are some errors in the code. Try implementing these fixes by following the steps below:

  1. Go to Shopify Theme Editor > Edit Code
  2. Update the code below in theme-editor.js

 

const selectVariantByClickingImage = {
  // Create variant images from productJson object
  _createVariantImage: function (product) {
    const variantImageObject = {};
    product.variants.forEach((variant) => {
      if (typeof variant.featured_image !== 'undefined' && variant.featured_image !== null) {
        const variantImage = variant.featured_image.src
          .split('?')[0]
          .replace(/http(s)?:/, '');
        variantImageObject[variantImage] = variantImageObject[variantImage] || {};
        product.options.forEach((option, index) => {
          const optionValue = variant.options[index];
          const optionKey = `option-${index}`;
          if (typeof variantImageObject[variantImage][optionKey] === 'undefined') {
            variantImageObject[variantImage][optionKey] = optionValue;
          } else {
            const oldValue = variantImageObject[variantImage][optionKey];
            if (oldValue !== null && oldValue !== optionValue) {
              variantImageObject[variantImage][optionKey] = optionValue;
            }
          }
        });
      }
    });
    return variantImageObject;
  },
  _updateVariant: function (event, id, product, variantImages) {
    const arrImage = event.src
      .split('?')[0]
      .replace(/http(s)?:/, '')
      .split('.');
    const strExtention = arrImage.pop();
    const strRemaining = arrImage.pop();
    const strNewImage = `${arrImage.join('.')}.${strRemaining}.${strExtention}`;
    
    if (typeof variantImages[strNewImage] !== 'undefined') {
      product.variants.forEach((option, index) => {
        const optionValue = variantImages[strNewImage][`option-${index}`];
        if (optionValue !== null && optionValue !== undefined) {
          const selects = document.querySelectorAll('#'+ id + ' [class*=select__select]');
          const options = selects[index].options;
          for (let option, n = 0; (option = options[n]); n += 1) {
            if (option.value === optionValue) {
              selects[index].selectedIndex = n;
              selects[index].dispatchEvent(new Event('change'));
              break;
            }
          }
        }
      });
    }
  },
  _selectVariant: function() {
    const productJson = document.querySelectorAll('[id^=ProductJson-');
    if (productJson.length > 0) {
      productJson.forEach((product) => {
        const sectionId = product.id.replace("ProductJson-", "MainProduct-");
        const thumbnails = document.querySelectorAll('#'+ sectionId + ' .thumbnail img');
        if (thumbnails.length > 1) {
          const productObject = JSON.parse(product.innerHTML);
          const variantImages = this._createVariantImage(productObject);
          var _this = this;
          document.addEventListener('click', function(e) {
              e = e || window.event;
              var target = e.target;
            if(target.classList.contains('thumbnail')){
              _this._updateVariant(target.querySelector('img'), sectionId, productObject, variantImages)
            }
          }, false);
        }
      });
    }
  },
};
if (document.readyState !== 'loading') {
  selectVariantByClickingImage._selectVariant();
} else {
  document.addEventListener(
    'DOMContentLoaded',
    selectVariantByClickingImage._selectVariant(),
  );
}

 

  • Add this code before </head> in theme.liquid:

 

<script src="{{ 'theme-editor.js' | asset_url }}" defer="defer"></script>​

 

  • Add this code in the section: sections/main-product.liquid

 

{% unless product == empty %}
  <script type="application/json" id="ProductJson-{{ section.id }}">
    {{ product | json }}
  </script>
{% endunless %}
​

 

This should integrate the required feature into your thumbnail layout. Let us know if this works for you. If you find this suggestion helpful, please consider liking us and accepting this as the solution. Happy building 🔨😀

Please let us know if you find it helpful by giving us a LIKE and Mark as Solution. Layoutbase is a leading Shopify page builder. Give us a try!
Vaseformyplace
Visitor
3 0 0

Hi @layoutbase ! 

I followed your instructions and I’m still stuck. I removed the old codes and added the ones you’ve instructed, is there something I’m doing wrong? Is there a different code I should use to make this user friendly with a mobile device? 

layoutbase
Pathfinder
111 13 24

Hi @Vaseformyplace,

Could you elaborate a little more about the specific problem you are encoutering? The code should be optimized for mobile as well.

 

I checked a few of the product pages just now, including this one: https://vaseformyplace.com/products/y-dshh-mini-creative-nordic-style-resin-flower-vase-decoration-h... The code seems to be work as intended, the dropdown change to the variant selected from the gallery:

 

variant-solution.png

 

Looking forward to your reply!

 

 

 

Please let us know if you find it helpful by giving us a LIKE and Mark as Solution. Layoutbase is a leading Shopify page builder. Give us a try!
timeforhelp
Visitor
1 0 0

I'm having the same problem, when I use the code and instructions you provided nothing changes, it looks and behaves the exact same as before I followed your instructions. The expected behavior I'm looking for is outlined in this document: https://help.shopify.com/en/manual/online-store/themes/themes-by-shopify/vintage-themes/customizing-...

layoutbase
Pathfinder
111 13 24

Hi @timeforhelp 

 

May I know which theme and theme version you are using? The code provided is theme specific such that the function can integrate into a Shopify's 2.0 theme. A different theme might behave differently. If you want this function as a global feature, it will require more complex code development. If you want more assistance, you can send a request here and we can go from there.

 

Best regards,

Layoutbase

Please let us know if you find it helpful by giving us a LIKE and Mark as Solution. Layoutbase is a leading Shopify page builder. Give us a try!
Jose37
Tourist
4 1 2

Hi,

I'm using Craft 5.0.0, followed your steps and it didn't worked for me.

Since i'm not used to this, maybe i pasted the code into the wrong places.

May you specify where do i have to paste it?

Thank You

bromanciuc
Visitor
3 0 0

The code works, variant option updates in dropdown list as per variant image selected or clicked BUT when click "Add to cart" button, in the cart you get either the first option variant from the dropdown list or the one that you manually select in the dropdown list. 

So, the code just updates the variant option in dropdown list by variant image clicked.

How to update the code so that correct option is being added to the cart?

thanks  

bromanciuc
Visitor
3 0 0

Hi @layoutbase,

I have used your code initially and got the issue with wrong variant being added to cart (see my previous post). 

I have used ChatGPT to share a fix for my issue and I ended up in a modified version of the JavaScript _updateVariant function, which solves my add-to-cart issue.

 

Here is the modified _updateVariant function code:

 

 

  _updateVariant: function (event, id, product, variantImages) {
    const arrImage = event.src
      .split('?')[0]
      .replace(/http(s)?:/, '')
      .split('.');
    const strExtention = arrImage.pop();
    const strRemaining = arrImage.pop();
    const strNewImage = `${arrImage.join('.')}.${strRemaining}.${strExtention}`;
    
    if (typeof variantImages[strNewImage] !== 'undefined') {
      product.variants.forEach((variant) => {
        const variantId = variant.id;
        const variantOptions = variantImages[strNewImage];
        let isMatch = true;

        for (let i = 0; i < variant.options.length; i++) {
          if (variant.options[i] !== variantOptions[`option-${i}`]) {
            isMatch = false;
            break;
          }
        }

        if (isMatch) {
          // Update the variant ID in the form
          const variantInput = document.querySelector('#' + id + ' input[name="id"]');
          if (variantInput) {
            variantInput.value = variantId;
            variantInput.dispatchEvent(new Event('change', { bubbles: true }));
          }

          // Additional: trigger change event on the select elements
          const selects = document.querySelectorAll('#'+ id + ' .select__select');
          selects.forEach((select, index) => {
            select.selectedIndex = [...select.options].findIndex(
              option => option.value === variantOptions[`option-${index}`]
            );
            select.dispatchEvent(new Event('change', { bubbles: true })); // Trigger change event
          });
        }
      });
    }
  },

 

 

Now it works perfectly. Thank you!