Ad

Shopify Trigger Function On Variant Selection But Don't Override Existing Functionality

I am using the 'Loft' theme on Shopify. When I select a variant on the product page, the them updates the SKU and the price to that variant I need more functionality than this, as I would like to show the dimensions of each variant using metafields.

I have created a function and called it on variant select like this:

jQuery(function($) {
  new Shopify.OptionSelectors('productSelect', {
    product: {{ product | json }},
    onVariantSelected: selectCallback,
    enableHistoryState: true
  });
});

My function is called and I can perform my desired actions. But this stops the default actions from happening, like updating the price and SKU. Is there a way I can call both?

Ad

Answer

There are a number of ways to make this work.

Firstly you need to be aware of how your theme is natively handling variants. For loft it uses the theme.Variant object so custom variant selection is as easy as:

jQuery('#shopify-section-product-template').on('theme:variants:changed', function(evt, variantObj){

   console.log('theme event for '+ variantObj.sku); // limited view of variant.
   console.log(variantObj);
});

For themes that use the old Shopify.OptionSelectors you can either do this old school by overriding the selectCallback global function like:

(function(){
   var original_selectCallback = window.selectCallback;
   window.selectCallback = function(variant, selector) {
    original_selectCallback(variant, selector); // call the original function
    myCustomHandler(variant); // called with the full jsonified variant object.
};

})();

Finally most modern themes that I've dealt with and themes that use Shopify.OptionSelectors with enableHistoryState: true allow you to skip the messiness of overrides and install your own history handler. Here is where you'd need to have your own script/liquid assemble the JSON you'd need for getting variant and product properties:

document.addEventListener('DOMContentLoaded', function(){

function usePushState(handler){

    //modern themes use pushstate to track variant changes without reload
    function track (fn, handler, before) {
        return function interceptor () {
            if (before) {
                handler.apply(this, arguments);
                return fn.apply(this, arguments);
            } else {
                var result = fn.apply(this, arguments);
                handler.apply(this, arguments);
                return result;
            }
        };
    }

    var currentVariantId = null;
    function variantHandler () {
        var selectedVariantId = window.location.search.replace(/.*variant=(\d+).*/, '$1');
        console.log('checking variant change to '+ selectedVariantId);
        if(!selectedVariantId) return;
        if(selectedVariantId != currentVariantId){
            currentVariantId = selectedVariantId;
            handler(selectedVariantId);
        }
    }

    // Assign listeners
    window.history.pushState = track(history.pushState, variantHandler);
    window.history.replaceState = track(history.replaceState, variantHandler);
    window.addEventListener('popstate', variantHandler);
}


usePushState(function(variantId){
    console.log('variant: '+ variantId +' selected');
});
});
Ad
source: stackoverflow.com
Ad