Skip to content

Instantly share code, notes, and snippets.

@DanWebb
Last active September 15, 2015 07:21
Show Gist options
  • Save DanWebb/f6afc0a7ed2c1b141200 to your computer and use it in GitHub Desktop.
Save DanWebb/f6afc0a7ed2c1b141200 to your computer and use it in GitHub Desktop.
Variant option selection with tabs instead of select boxes and no need to initialise it in the product template.
// Product page variant option selection
var VariantSelect = (function() {
var $variantSelection;
// The selection filters from top to bottom. Only the 2nd and 3rd option
// variants can become unavailable
function setUnavailable(index) {
var option1 = $variantSelection.find('.active[data-index="0"]').data('option1');
if(index===0) {
// we need to set the unavailable items in indexes 1 & 2 (remember it's 0 index)
$variantSelection.find('span[data-index="1"]:not([data-option1="'+option1+'"]), span[data-index="2"]:not([data-option1="'+option1+'"])').addClass('unavailable').removeClass('active');
$variantSelection.find('span[data-index="1"][data-option1="'+option1+'"], span[data-index="2"][data-option1="'+option1+'"]').removeClass('unavailable');
}
else if(index===1) {
// we need to set the unavailable items in index 2
var option2 = $variantSelection.find('.active[data-index="1"]').data('option2');
$variantSelection.find('span[data-index="2"]:not([data-option1="'+option1+'"][data-option2="'+option2+'"])').addClass('unavailable').removeClass('active');
$variantSelection.find('span[data-index="2"][data-option1="'+option1+'"][data-option2="'+option2+'"]').removeClass('unavailable');
}
}
// make sure we still have an active option in each section and that all options
// are showing that should be
function setActive() {
$variantSelection.each(function() {
if(!$(this).find('span.active').length) $(this).find('span:not(.unavailable):first').addClass('active');
// make sure the active item is showing
if(!$(this).find('span.active:visible').length) {
var $activeItem = $(this).find('span.active');
var activeValue = $activeItem.data('val');
$(this).find('span[data-val="'+activeValue+'"]:visible').hide().after($activeItem);
$activeItem.show();
}
// make sure items that are not unavailable which have same name variants that
// are unavailable are swapped out
$(this).find('span.unavailable:visible').each(function() {
var itemText = $(this).data('val');
var $validItem = $(this).siblings('span[data-val="'+itemText+'"]:not(.unavailable):first');
if($validItem.length) {
$(this).hide().after($validItem);
$validItem.show();
}
});
});
}
function getActive() {
if($variantSelection.find('span.active[data-index="2"]').length) return $variantSelection.find('span.active[data-index="2"]');
if($variantSelection.find('span.active[data-index="1"]').length) return $variantSelection.find('span.active[data-index="1"]');
if($variantSelection.find('span.active[data-index="0"]').length) return $variantSelection.find('span.active[data-index="0"]');
}
// the last index will always hold the correct id
function setVariant() {
var $active = getActive();
$('[name="id"]').val($active.data('id'));
$('#ProductPrice').html($active.data('price'))
}
function selectItem() {
if($(this).hasClass('unavailable')) return;
$(this).toggleClass('active').siblings('span').removeClass('active');
var index = $(this).data('index');
setUnavailable(index);
setActive();
setId();
}
function init() {
if(!$('.variant-selection').length) return;
$variantSelection = $('.variant-selection');
$variantSelection.find('span').click(selectItem);
setActive();
setVariant();
}
return function() {
$(init);
};
})();
// initialise it
VariantSelect();
<form action="/cart/add" method="post" enctype="multipart/form-data" id="AddToCartForm" class="form-vertical">
<!-- Product Price ===================== -->
<div itemprop="price" class="product-price">
<span id="ProductPrice">{{ current_variant.price | money }}</span>
<!-- on sale -->
{% if current_variant.compare_at_price > current_variant.price %}
&nbsp;<span class="h2">was</span> <span class="h2 line-through">{{ current_variant.compare_at_price | money }}</span>
{% endif %}
</div>
<!-- //Product Price -->
<!--
Variant Selection =====================
Generate a set of tags for each of the variant options.
-- option_list ensures we don't list the same variant option twice.
-- class="active" represents the currently selected option
-- class="unavailable" greys out the options preventing it from being selected
-- when an option is selected each data-option(1/2/3) is checked in the VariantSelect js to
ensure only compatible matches can be selected
-->
{% if product.available %}
{% for option in product.options %}
{% assign option_index = forloop.index0 %}
{% assign option_list = '' %}
{% assign selected_variant = product.selected_or_first_available_variant %}
<div class="variant-selection">
<h4>{{ option }}:</h4>
{% for variant in product.variants %}
{% if variant.available %}
{% if option_list contains variant.options[option_index] %}
<!-- hidden tags (get swapped out when a relevant option is chosen) -->
{% if option_index != 0 %}<span style="display:none;" data-id="{{ variant.id }}" data-index="{{ option_index }}" data-option1="{{ variant.options[0] }}" data-option2="{{ variant.options[1] }}" data-option3="{{ variant.options[2] }}" data-val="{{ variant.options[option_index] }}" data-price="{{ variant.price | money }}">{{ variant.options[option_index] }}</span>{% endif %}
{% else %}
{% assign option_list = option_list | append: variant.options[option_index] | append: ', ' %}
<span
class="{% if variant == selected_variant %}active{% endif %} {% unless variant.options[0] == selected_variant.options[0] %}{% if option_index != 0 %}unavailable{% endif %}{% endunless %}"
data-id="{{ variant.id }}"
data-index="{{ option_index }}"
data-option1="{{ variant.options[0] }}"
data-option2="{{ variant.options[1] }}"
data-option3="{{ variant.options[2] }}"
data-val="{{ variant.options[option_index] }}"
data-price="{{ variant.price | money }}"
>{{ variant.options[option_index] }}</span>
{% endif %}
{% endif %}
{% endfor %}
</div>
{% endfor %}
{% endif %}
<!-- //Variant Select -->
<!-- Form Controls ===================== -->
<label for="Quantity" class="quantity-selector">{{ 'products.product.quantity' | t }}</label>
<input type="number" id="Quantity" name="quantity" value="1" min="1" class="quantity-selector">
<!-- the current variant id is stored here and submitted with the form -->
<input type="hidden" data-id="{{ product.selected_or_first_available_variant.id }}" name="id">
<button type="submit" name="add" id="AddToCart" class="btn">
<span id="AddToCartText">{{ 'products.product.add_to_cart' | t }}</span>
</button>
<!-- //Form Controls -->
</form>
.variant-selection {
margin: 10px -10px 10px -10px;
h4 { margin: 0 0 3px 10px; }
span {
display: inline-block;
border-radius: 20px;
border: 1px solid $dark-shade;
color: $dark-shade;
padding: 8px 10px;
font-weight: 300;
margin: 5px 10px;
background: #fff;
cursor: pointer;
}
span.active { background: $primary-4; border-color: $primary-4; color: #fff; }
span.unavailable { background: $light-shade; border-color: $light-shade; color: $mid-shade; cursor: default; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment