Single variant dropdown vs. multi-option default

Highlighted
Tourist
10 0 1

CoverMe posed essentially the question I want to get answered as well... How do I display a product variant as a single drop down, e.g., Select [ color / size / fit ] versus the new Shopify standard of multiple drops per product option.

The problem for my customer is that while the Shopify default solution prevents displaying a "Sold Out" or "Unavailable" product on page load (see Auto-selecting the first available variant so that your product does not look sold out) it doesn't prevent a user from later choosing a combination that is unavailable or sold out. My customer believes this is major problem, considering option combinations would result in often seeing "Unavailable."

To address that, the customer desires to have a single drop down.

How is this accomplished yet still providing the call back to display the pricing, etc?

I've hacked the hell out of the default Shopify.OptionsSelector constructor and the Liquid template trying to get there, but the obvious has been eluding me.

Since all the theme templates now use the multi-option drop downs, I can't find an example of "how it use to work."

0 Likes
Highlighted
Shopify Expert
4118 28 378

It is totally simple to not allow customers to choose unavailable inventory. Not only is there a recipe for free on the wiki for that, but you could roll your own in a second or two. 

Notice in the callback there is code that detects a variant selected? If the variant is not available, you can alert the customer and not allow the add to cart to occur. 

That's 2 solutions....and I am sure there are 10 or 20 others if you really need more... 

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
0 Likes
Highlighted
Tourist
10 0 1

@HunkyBill... I'm aware that all Shopify themes now "prevent" the addition of unavailable products. One need not look further than the wiki entry on this topic (cited in the original post). 

This is not the problem. The problem is: the multi-select variant options now used by default, e.g.,

Color: [red [v]
Size:  [S    [v]
Fit:     [Loose [v]

is not desired by my client.

But:

Choose: [ red / S / Loose [v]

How do I get the Liquid/Shopify.OptionsSelector display to show one select by variant (not multiple options by variant)? 

My customer does not wish to use the multi-options select by variant.

 

 

0 Likes
Highlighted
Tourist
10 0 1

attaching an image... this is what I need to get to for the client (actually I'm already there as shown) save that the onVariantSelected callback (selectedCallback) no longer functions. This means that the price won't display.

Can anyone point me to a wiki or other post showing how they got  the price to display using a "single selector for product."

Remember, "Unavailable" is not an option for my client, so the "multi selector for product" (the default Shopify theme presentation) is not satisfactory for the client.

0 Likes
Highlighted
Tourist
10 0 1

Should I cross post to this Shopify Design? Seems that maybe the audience in this forum is not the right one.

Tim

0 Likes
Highlighted
Shopify Expert
4118 28 378

If you just render variants in a select element, you get the behaviour you want. Just inspect the availability of the variant and don't render unavailable variants. And if you want an icon in your select element options, that is just CSS. 

You do know you can just loop through variants right? 

{% for variant in product.variants %}

and now you have access to your  red / S / Loose

This is in fact was how Shopify worked like 6 years ago before the options selector code even existed.


Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
0 Likes
Highlighted
Tourist
10 0 1

Yes, I'm doing exactly that. Thank you.

However, the ability to display a product.variant price is broken because selectCallback is not called (the callback is assigned to the onVariantSelected property of the options object passed to Shopify.OptionSelectors constructor). I need to restore this functionality, but the selectCallback in married to the Shopify.OptionSelectors through the Shopify.Products object and the variant assigned in the collection.

I can call the selectCallback directly, or set my own event handler, but constructing the variant appears to be nontrivial. Though I'm a JavaScript developer and will solve this, sometimes a friendly hint from those more familiar with the APIs goes a long way.

0 Likes
Highlighted
Shopify Expert
4118 28 378

If you want to dynamically update the price, based on a change in variant then you can always do the following:

Store the products JSON in a variable. Now you have ALL the variants and all their prices.

Add a change listener to the select element you assigned to hold the variants. Obviously, you can store the variant ID as the value of the option element. 

When a change event fires on the select, send the ID to a function you write that get the price. Since you can match an ID to an ID, this is trivial. Now, update the price in the DOM, and voila.. in just minutes, you've got nice pricing changes, and NO need for option selector JS, nor it's callback.

 

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
0 Likes
Highlighted
Tourist
10 0 1

Solved this, with some help from HunkyHill.

Most themes implement the following code in product.liquid:

<script type="text/javascript">
// <![CDATA[  
var selectCallback = function(variant, selector) {
  if (variant && variant.available == true) {
    // selected a valid variant
    // ... set price ..
  } else {
    // variant doesn't exist
    // ... "Unavailable" ...
  }
};

// initialize multi selector for product      
jQuery(document).ready(function() {
  new Shopify.OptionSelectors("product-select", { product: {{ product | json }}, onVariantSelected: selectCallback });

  // ... removed code for brevity ...

});                         
// ]]>
</script>

Basically, removing the call to Shopify.OptionSelectors reverts most themes to early Shopify presentations. However, if you don't read JavaScript, you might not guess that removing this code will break other features like pricing and availability messages. This functionality is provided in the callback property "onVariantSelected". 

To provide a single option selector and retain the pricing display, I replaced the JQuery DOM Ready call with the following:

// initialize multi selector for product      

jQuery(document).ready(function() {
	var product_json = {{ product | json }};
	jQuery("#optlist").html(product_json.options.join(", "));			
	jQuery('#product-select').change(function(e) { 
		var t = e.target || e.srcElement,
		    variantId = t.options[t.selectedIndex].value;
		    variant = null;
		
		for(var v = 0, l = product_json.variants.length; v < l; v = v + 1 ) {
			if(product_json.variants[v].id == variantId) {
				variant = product_json.variants[v];
				selectCallback(variant);
				break;
			}
		}
	 });
   jQuery('#product-select').change();
});                         

// ... code removed for brevity ...
// ]]>
</script>

Pretty straightforward JavaScript.

  1. Get the product as JSON
  2. Join the product options for display
  3. Assign an anonymous function to the onchange event of the select element that gets the currently selected variant by matching it in a loop
  4. Pass the variant to the existing selectCallback

1 Like
Highlighted
New Member
1 0 0

Here is almost the same solution in vanilla javascript. The changeVariant() function gets called by the html select with all the variants inside. selectCallback() is than used to process all the changes that need to be done based on the chosen variant.

function changeVariant() {
  let variantSelect = document.getElementById("variant-select");
  let variantId = variantSelect.options[variantSelect.selectedIndex].value;
  let variant = null;
  for(var v = 0; v < product_json.variants.length; v++) {
    if(product_json.variants[v].id == variantId) {
    variant = product_json.variants[v];
    // callback for anything that has to change on variant switch
    selectCallback(variant);
break;
}
}
}
0 Likes