Discuss and resolve questions on Liquid, JavaScript, themes, sales channels, and site speed enhancements.
Hi! I created a custom variant dropdown using the prettydropdown jquery plugin. I added functionality to display a label "In Stock" if the variant is in stock, otherwise "Custom Made" if it is out of stock or is not tracking quantity. Also if the product is tagged "2 Weeks" it displays a 2-week message and if they are tagged "4-6 Weeks" a 4-6 week message. Here is a preview of a product page.
Now I need also to display the variant label and message somewhere else on the page. I ended up adding an HTML block to the product with this code: <div class="stock-message"></div>. The issue I am having is the stock message to display the actual value on page load instead of "undefined". I know it is embedded in a click function but I have tried numerous other ways and nothing is working. The eventlistener function is working perfectly, it's the $(function() { that needs something changed about it, whether its placement or something else. Below is the code for the stock message. Further below it (not shown) is the rest of the code for the message and label in the dropdown. I would really appreciate some help! Thanks!
setTimeout(function(){
$('.variant-input-wrap').find('li').click(function() {
changetext($(this));
})
changetext($('.variant-input-wrap').eq(0).find('li').eq(0));
},1000)
function changetext(element){
var current_option = element.attr('data-value');
var variant_label = "<span class='variant-label'>";
var variant_message = "<span class='variant-message'>";
var close_span = "</span>";
$(function() {
if($.trim($('.prettydropdown li.selected .variant-message').html())=='') {
$('.stock-message').html(variant_label + $('.prettydropdown li.selected .variant-label').html() + close_span);
} else {
$('.stock-message').html(variant_label + $('.prettydropdown li.selected .variant-label').html() + close_span + variant_message + $('.prettydropdown li.selected .variant-message').html() + close_span);
}
});
document.addEventListener('variant:change', function(event) {
if($.trim($('.prettydropdown li.selected .variant-message').html())=='') {
$('.stock-message').html(variant_label + $('.prettydropdown li.selected .variant-label').html() + close_span);
} else {
$('.stock-message').html(variant_label + $('.prettydropdown li.selected .variant-label').html() + close_span + variant_message + $('.prettydropdown li.selected .variant-message').html() + close_span);
}
}.bind(this));
Solved! Go to the solution
This is an accepted solution.
Hi @michaelmorgan,
Please change all code:
/*!
* jQuery Pretty Dropdowns Plugin v4.17.0 by T. H. Doan (https://thdoan.github.io/pretty-dropdowns/)
*
* jQuery Pretty Dropdowns by T. H. Doan is licensed under the MIT License.
* Read a copy of the license in the LICENSE file or at https://choosealicense.com/licenses/mit/
*/
(function($) {
$.fn.prettyDropdown = function(oOptions) {
// Default options
oOptions = $.extend({
classic: true,
customClass: 'arrow',
width: null,
height: 50,
hoverIntent: -1,
multiDelimiter: '; ',
multiVerbosity: 99,
selectedMarker: '✓',
afterLoad: function(){}
}, oOptions);
oOptions.selectedMarker = '<span aria-hidden="true" class="checked"> ' + oOptions.selectedMarker + '</span>';
// Validate options
if (isNaN(oOptions.width) && !/^\d+%$/.test(oOptions.width)) oOptions.width = null;
if (isNaN(oOptions.height)) oOptions.height = 50;
else if (oOptions.height<8) oOptions.height = 8;
if (isNaN(oOptions.hoverIntent)) oOptions.hoverIntent = 200;
if (isNaN(oOptions.multiVerbosity)) oOptions.multiVerbosity = 99;
// Translatable strings
var MULTI_NONE = 'None selected',
MULTI_PREFIX = 'Selected: ',
MULTI_POSTFIX = ' selected';
// Globals
var $current,
aKeys = [
'0','1','2','3','4','5','6','7','8','9',,,,,,,,
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'
],
nCount,
nHoverIndex,
nLastIndex,
nTimer,
nTimestamp,
// Initiate pretty drop-downs
init = function(elSel) {
var $select = $(elSel),
nSize = elSel.size,
sId = elSel.name || elSel.id || '',
sLabelId;
// Exit if widget has already been initiated
if ($select.data('loaded')) return;
// Remove 'size' attribute to it doesn't affect vertical alignment
$select.data('size', nSize).removeAttr('size');
// Set <select> height to reserve space for <div> container
$select.css('display', 'none').outerHeight(oOptions.height);
nTimestamp = performance.now()*100000000000000;
// Test whether to add 'aria-labelledby'
if (elSel.id) {
// Look for <label>
var $label = $('label[for=' + elSel.id + ']');
if ($label.length) {
// Add 'id' to <label> if necessary
if ($label.attr('id') && !/^menu\d{13,}$/.test($label.attr('id'))) sLabelId = $label.attr('id');
else $label.attr('id', (sLabelId = 'menu' + nTimestamp));
}
}
nCount = 0;
var $items = $('optgroup, option', $select),
$selected = $items.filter(':selected'),
bMultiple = elSel.multiple,
// Height - 2px for borders
sHtml = '<ul' + (elSel.disabled ? '' : ' tabindex="0"') + ' role="listbox"'
+ (elSel.title ? ' title="' + elSel.title + '" aria-label="' + elSel.title + '"' : '')
+ (sLabelId ? ' aria-labelledby="' + sLabelId + '"' : '')
+ ' aria-activedescendant="item' + nTimestamp + '-1" aria-expanded="false"'
+ ' style="max-height:' + (oOptions.height-2) + 'px;margin:'
// NOTE: $select.css('margin') returns an empty string in Firefox, so we have to get
// each margin individually. See https://github.com/jquery/jquery/issues/3383
+ $select.css('margin-top') + ' '
+ $select.css('margin-right') + ' '
+ $select.css('margin-bottom') + ' '
+ $select.css('margin-left') + ';">';
if (bMultiple) {
sHtml += renderItem(null, 'selected');
$items.each(function() {
if (this.selected) {
sHtml += renderItem(this, '', true)
} else {
sHtml += renderItem(this);
}
});
} else {
if (oOptions.classic) {
$items.each(function() {
sHtml += renderItem(this);
});
} else {
sHtml += renderItem($selected[0], 'selected');
$items.filter(':not(:selected)').each(function() {
sHtml += renderItem(this);
});
}
}
sHtml += '</ul>';
$select.wrap('<div ' + (sId ? 'id="prettydropdown-' + sId + '" ' : '')
+ 'class="prettydropdown '
+ (oOptions.classic ? 'classic ' : '')
+ (elSel.disabled ? 'disabled ' : '')
+ (bMultiple ? 'multiple ' : '')
+ oOptions.customClass + ' loading"'
// NOTE: For some reason, the container height is larger by 1px if the <select> has the
// 'multiple' attribute or 'size' attribute with a value larger than 1. To fix this, we
// have to inline the height.
+ ((bMultiple || nSize>1) ? ' style="height:' + oOptions.height + 'px;"' : '')
+'></div>').before(sHtml).data('loaded', true);
var $dropdown = $select.parent().children('ul'),
nWidth = $dropdown.outerWidth(true),
nOuterWidth;
$items = $dropdown.children();
// Update default selected values for multi-select menu
if (bMultiple) updateSelected($dropdown);
else if (oOptions.classic) $('[data-value="' + $selected.val().replace(/"/g, '″') + '"]', $dropdown).addClass('selected').append(oOptions.selectedMarker);
// Calculate width if initially hidden
if ($dropdown.width()<=0) {
var $clone = $dropdown.parent().clone().css({
position: 'absolute',
top: '-100%'
});
$('body').append($clone);
nWidth = $clone.children('ul').outerWidth(true);
$('li', $clone).width(nWidth);
nOuterWidth = $clone.children('ul').outerWidth(true);
$clone.remove();
}
// Set dropdown width and event handler
// NOTE: Setting width using width(), then css() because width() only can return a float,
// which can result in a missing right border when there is a scrollbar.
$items.width(nWidth).css('width', $items.css('width'));
if (oOptions.width) {
$dropdown.parent().css('min-width', $items.css('width'));
$dropdown.css('width', '100%');
$items.css('width', '100%');
}
$items.click(function() {
var $li = $(this),
$selected = $dropdown.children('.selected');
// Ignore disabled menu
if ($dropdown.parent().hasClass('disabled')) return;
// Only update if not disabled, not a label, and a different value selected
if ($dropdown.hasClass('active') && !$li.hasClass('disabled') && !$li.hasClass('label') && $li.data('value').toString().replace(/"/g, '″')!==$selected.data('value').toString().replace(/"/g, '″')) {
// Select highlighted item
if (bMultiple) {
if ($li.children('span.checked').length) $li.children('span.checked').remove();
else $li.append(oOptions.selectedMarker);
// Sync <select> element
$dropdown.children(':not(.selected)').each(function(nIndex) {
$('optgroup, option', $select).eq(nIndex).prop('selected', $(this).children('span.checked').length>0);
});
// Update selected values for multi-select menu
updateSelected($dropdown);
} else {
$selected.removeClass('selected').children('span.checked').remove();
$li.addClass('selected').append(oOptions.selectedMarker);
if (!oOptions.classic) $dropdown.prepend($li);
$dropdown.removeClass('reverse').attr('aria-activedescendant', $li.attr('id'));
if ($selected.data('group') && !oOptions.classic) $dropdown.children('.label').filter(function() {
return $(this).text()===$selected.data('group');
}).after($selected);
// Sync <select> element
$('optgroup, option', $select).filter(function() {
// <option>: this.value = this.text, $li.data('value') = $li.contents()
// <option value="">: this.value = "", $li.data('value') = undefined
return (this.value.replace(/"/g, '″')+'|'+this.text.replace(/"/g, '″'))===($li.data('value')||'')+'|'+$li.contents().filter(function() {
// Filter out selected marker
return this.nodeType===3;
}).text();
}).prop('selected', true);
}
$select.get(0).dispatchEvent(new Event('change'))
}
if ($li.hasClass('selected') || !bMultiple) {
$dropdown.toggleClass('active');
$dropdown.attr('aria-expanded', $dropdown.hasClass('active'));
}
// Try to keep drop-down menu within viewport
if ($dropdown.hasClass('active')) {
// Close any other open menus
if ($('.prettydropdown > ul.active').length>1) {
resetDropdown($('.prettydropdown > ul.active').not($dropdown));
$('.prettydropdown > ul.active').not($dropdown).removeClass('active');
}
var nWinHeight = window.innerHeight,
nMaxHeight,
nOffsetTop = $dropdown.offset().top,
nScrollTop = $(document).scrollTop(),
nDropdownHeight = $dropdown.outerHeight();
if (nSize) {
nMaxHeight = nSize*(oOptions.height-2);
if (nMaxHeight<nDropdownHeight-2) nDropdownHeight = nMaxHeight+2;
}
var nDropdownBottom = nOffsetTop-nScrollTop+nDropdownHeight;
if (nDropdownBottom>nWinHeight) {
// Expand to direction that has the most space
if (nOffsetTop-nScrollTop>nWinHeight-(nOffsetTop-nScrollTop+oOptions.height)) {
$dropdown.addClass('reverse');
if (!oOptions.classic) $dropdown.append($selected);
if (nOffsetTop-nScrollTop+oOptions.height<nDropdownHeight) {
$dropdown.outerHeight(nOffsetTop-nScrollTop+oOptions.height);
// Ensure the selected item is in view
$dropdown.scrollTop(nDropdownHeight);
}
} else {
$dropdown.height($dropdown.height()-(nDropdownBottom-nWinHeight));
}
}
if (nMaxHeight && nMaxHeight<$dropdown.height()) $dropdown.css('height', nMaxHeight + 'px');
// Ensure the selected item is in view
if (oOptions.classic) $dropdown.scrollTop($selected.index()*(oOptions.height-2));
} else {
$dropdown.data('clicked', true);
resetDropdown($dropdown[0]);
}
});
$dropdown.on({
focusin: function() {
// Unregister any existing handlers first to prevent duplicate firings
$(window).off('keydown', handleKeypress).on('keydown', handleKeypress);
},
focusout: function() {
$(window).off('keydown', handleKeypress);
},
mouseenter: function() {
$dropdown.data('hover', true);
},
mouseleave: resetDropdown,
mousemove: hoverDropdownItem
});
if (oOptions.hoverIntent<0) {
$(document).click(function(e) {
if ($dropdown.data('hover') && !$dropdown[0].contains(e.target)) resetDropdown($dropdown[0]);
});
}
// Put focus on menu when user clicks on label
if (sLabelId) $('#' + sLabelId).off('click', handleFocus).click(handleFocus);
// Done with everything!
$dropdown.parent().width(oOptions.width||nOuterWidth||$dropdown.outerWidth(true)).removeClass('loading');
oOptions.afterLoad();
},
// Manage widget focusing
handleFocus = function(e) {
$('ul[aria-labelledby=' + e.target.id + ']').focus();
},
// Manage keyboard navigation
handleKeypress = function(e) {
var $dropdown = $('.prettydropdown > ul.active, .prettydropdown > ul:focus');
if (!$dropdown.length) return;
if (e.which===9) { // Tab
resetDropdown($dropdown[0]);
return;
} else {
// Intercept non-Tab keys only
e.preventDefault();
e.stopPropagation();
}
var $items = $dropdown.children(),
bOpen = $dropdown.hasClass('active'),
nItemsHeight = $dropdown.height()/(oOptions.height-2),
nItemsPerPage = nItemsHeight%1<0.5 ? Math.floor(nItemsHeight) : Math.ceil(nItemsHeight),
sKey;
nHoverIndex = Math.max(0, $dropdown.children('.hover').index());
nLastIndex = $items.length-1;
$current = $items.eq(nHoverIndex);
$dropdown.data('lastKeypress', +new Date());
switch (e.which) {
case 13: // Enter
if (!bOpen) {
$current = $items.filter('.selected');
toggleHover($current, 1);
}
$current.click();
break;
case 27: // Esc
if (bOpen) resetDropdown($dropdown[0]);
break;
case 32: // Space
if (bOpen) {
sKey = ' ';
} else {
$current = $items.filter('.selected');
toggleHover($current, 1);
$current.click();
}
break;
case 33: // Page Up
if (bOpen) {
toggleHover($current, 0);
toggleHover($items.eq(Math.max(nHoverIndex-nItemsPerPage-1, 0)), 1);
}
break;
case 34: // Page Down
if (bOpen) {
toggleHover($current, 0);
toggleHover($items.eq(Math.min(nHoverIndex+nItemsPerPage-1, nLastIndex)), 1);
}
break;
case 35: // End
if (bOpen) {
toggleHover($current, 0);
toggleHover($items.eq(nLastIndex), 1);
}
break;
case 36: // Home
if (bOpen) {
toggleHover($current, 0);
toggleHover($items.eq(0), 1);
}
break;
case 38: // Up
if (bOpen) {
toggleHover($current, 0);
// If not already key-navigated or first item is selected, cycle to the last item; or
// else select the previous item
toggleHover(nHoverIndex ? $items.eq(nHoverIndex-1) : $items.eq(nLastIndex), 1);
}
break;
case 40: // Down
if (bOpen) {
toggleHover($current, 0);
// If last item is selected, cycle to the first item; or else select the next item
toggleHover(nHoverIndex===nLastIndex ? $items.eq(0) : $items.eq(nHoverIndex+1), 1);
}
break;
default:
if (bOpen) sKey = aKeys[e.which-48];
}
if (sKey) { // Alphanumeric key pressed
clearTimeout(nTimer);
$dropdown.data('keysPressed', $dropdown.data('keysPressed')===undefined ? sKey : $dropdown.data('keysPressed') + sKey);
nTimer = setTimeout(function() {
$dropdown.removeData('keysPressed');
// NOTE: Windows keyboard repeat delay is 250-1000 ms. See
// https://technet.microsoft.com/en-us/library/cc978658.aspx
}, 300);
// Build index of matches
var aMatches = [],
nCurrentIndex = $current.index();
$items.each(function(nIndex) {
if ($(this).text().toLowerCase().indexOf($dropdown.data('keysPressed'))===0) aMatches.push(nIndex);
});
if (aMatches.length) {
// Cycle through items matching key(s) pressed
for (var i=0; i<aMatches.length; ++i) {
if (aMatches[i]>nCurrentIndex) {
toggleHover($items, 0);
toggleHover($items.eq(aMatches[i]), 1);
break;
}
if (i===aMatches.length-1) {
toggleHover($items, 0);
toggleHover($items.eq(aMatches[0]), 1);
}
}
}
}
},
// Highlight menu item
hoverDropdownItem = function(e) {
var $dropdown = $(e.currentTarget);
if (e.target.nodeName!=='LI' || !$dropdown.hasClass('active') || new Date()-$dropdown.data('lastKeypress')<200) return;
toggleHover($dropdown.children(), 0, 1);
toggleHover($(e.target), 1, 1);
},
// Construct menu item
// elOpt is null for first item in multi-select menus
renderItem = function(elOpt, sClass, bSelected) {
var sGroup = '',
sText = '',
sTitle;
sClass = sClass || '';
if (elOpt) {
switch (elOpt.nodeName) {
case 'OPTION':
if (elOpt.parentNode.nodeName==='OPTGROUP') sGroup = elOpt.parentNode.getAttribute('label');
sText = (elOpt.getAttribute('data-prefix') || '') + elOpt.text + (elOpt.getAttribute('data-suffix') || '');
break;
case 'OPTGROUP':
sClass += ' label';
sText = (elOpt.getAttribute('data-prefix') || '') + elOpt.getAttribute('label') + (elOpt.getAttribute('data-suffix') || '');
break;
}
// if (elOpt.disabled || (sGroup && elOpt.parentNode.disabled)) sClass += ' disabled';
sTitle = elOpt.title;
if (sGroup && !sTitle) sTitle = elOpt.parentNode.title;
}
++nCount;
return '<li id="item' + nTimestamp + '-' + nCount + '"'
+ (sGroup ? ' data-group="' + sGroup + '"' : '')
+ (elOpt && (elOpt.value||oOptions.classic) ? ' data-value="' + elOpt.value.replace(/"/g, '″') + '"' : '')
+ (elOpt && elOpt.nodeName==='OPTION' ? ' role="option"' : '')
+ (sTitle ? ' title="' + sTitle + '" aria-label="' + sTitle + '"' : '')
+ (sClass ? ' class="' + $.trim(sClass) + '"' : '')
+ ((oOptions.height!==50) ? ' style="height:' + (oOptions.height-2)
+ 'px;line-height:' + (oOptions.height-4) + 'px;"' : '') + '>' + sText
+ ((bSelected || sClass==='selected') ? oOptions.selectedMarker : '') + '</li>';
},
// Reset menu state
// @param o Event or Element object
resetDropdown = function(o) {
if (oOptions.hoverIntent<0 && o.type==='mouseleave') return;
var $dropdown = $(o.currentTarget||o);
$dropdown.data('hover', false);
clearTimeout(nTimer);
nTimer = setTimeout(function() {
if ($dropdown.data('hover')) return;
if ($dropdown.hasClass('reverse') && !oOptions.classic) $dropdown.prepend($dropdown.children(':last-child'));
$dropdown.removeClass('active reverse').removeData('clicked').attr('aria-expanded', 'false').css('height', '');
$dropdown.children().removeClass('hover nohover');
// Update focus for NVDA screen readers
$dropdown.attr('aria-activedescendant', $dropdown.children('.selected').attr('id'));
}, (o.type==='mouseleave' && !$dropdown.data('clicked')) ? oOptions.hoverIntent : 0);
},
// Set menu item hover state
// bNoScroll set on hoverDropdownItem()
toggleHover = function($li, bOn, bNoScroll) {
if (bOn) {
var $dropdown = $li.parent();
$li.removeClass('nohover').addClass('hover');
// Update focus for NVDA screen readers
$dropdown.attr('aria-activedescendant', $li.attr('id'));
if ($li.length===1 && $current && !bNoScroll) {
// Ensure items are always in view
var nDropdownHeight = $dropdown.outerHeight(),
nItemOffset = $li.offset().top-$dropdown.offset().top-1; // -1px for top border
if ($li.index()===0) {
$dropdown.scrollTop(0);
} else if ($li.index()===nLastIndex) {
$dropdown.scrollTop($dropdown.children().length*oOptions.height);
} else {
if (nItemOffset+oOptions.height>nDropdownHeight) $dropdown.scrollTop($dropdown.scrollTop()+oOptions.height+nItemOffset-nDropdownHeight);
else if (nItemOffset<0) $dropdown.scrollTop($dropdown.scrollTop()+nItemOffset);
}
}
} else {
$li.removeClass('hover').addClass('nohover');
}
},
// Update selected values for multi-select menu
updateSelected = function($dropdown) {
var $select = $dropdown.parent().children('select'),
aSelected = $('option', $select).map(function() {
if (this.selected) return this.text;
}).get(),
sSelected;
if (oOptions.multiVerbosity>=aSelected.length) sSelected = aSelected.join(oOptions.multiDelimiter) || MULTI_NONE;
else sSelected = aSelected.length + '/' + $('option', $select).length + MULTI_POSTFIX;
if (sSelected) {
var sTitle = ($select.attr('title') ? $select.attr('title') : '') + (aSelected.length ? '\n' + MULTI_PREFIX + aSelected.join(oOptions.multiDelimiter) : '');
$dropdown.children('.selected').text(sSelected);
$dropdown.attr({
'title': sTitle,
'aria-label': sTitle
});
} else {
$dropdown.children('.selected').empty();
$dropdown.attr({
'title': $select.attr('title'),
'aria-label': $select.attr('title')
});
}
};
setTimeout(function(){
$('.variant-input-wrap').find('li').click(function() {
changetext($(this));
})
changetext($('.variant-input-wrap').eq(0).find('li').eq(0));
$('.stock-message').ready(function() {
stockMessage($(this));
})
},1000)
function stockMessage() {
// var variant_message = $('.variant-wrapper').last().find('.variant-message').html();
// $('.hidden-variant option').first().ready(function() {
// if($(this).attr('data-available')=='true') {
// $('.stock-message').html("<span class='variant-label'>" + "In Stock" + "</span>");
// } else {
// $('.stock-message').html("<span class='variant-label'>" + "Custom Made" + "</span>" + "<span class='variant-message'>" + variant_message + "</span>");
// }
// });
}
function changetext(element){
var current_option = element.attr('data-value');
document.addEventListener('variant:change', function(event) {
if($.trim($('.prettydropdown li.selected .variant-message').html())=='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>");
} else if($.trim($('.prettydropdown li.selected .variant-message').html())!='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>" + "<span class='variant-message'>" + $('.prettydropdown li.selected .variant-message').html() + "</span>");
}
}.bind(this));
setTimeout(function(){
$('.variant-input-wrap').last().find('li').each(function(){
if( $('.variant-input-wrap').eq(2).length > 0){
var first_option = $('.variant-input-wrap').eq(0).find('.selected').attr('data-value');
var second_option = $('.variant-input-wrap').eq(1).find('.selected').attr('data-value');
var current_elem = $(this);
var unavailable = false;
$('.hidden-variant option').each(function(){
if($(this).attr('value') == first_option + ' / ' + second_option + ' / ' + current_elem.attr('data-value') && $(this).attr('data-available') == 'true'){
current_elem.html(current_elem.attr('data-value') + '<span class="variant-label">In Stock</span>');
unavailable = true;
}
})
if(!unavailable){
current_elem.html($(this).attr('data-value') + '<span class="variant-label">Custom Made</span>'+ '<span class="variant-message">' + $('.hidden-variant option').attr('data-text') + '</span>');
}
}
else if( $('.variant-input-wrap').eq(1).length > 0){
var first_option = $('.variant-input-wrap').eq(0).find('.selected').attr('data-value');
var current_elem = $(this);
var unavailable = false;
$('.hidden-variant option').each(function(){
if($(this).attr('value') == first_option +' / ' + current_elem.attr('data-value') && $(this).attr('data-available') == 'true'){
current_elem.html(current_elem.attr('data-value') + '<span class="variant-label">In Stock</span>');
unavailable = true;
}
})
if(!unavailable){
current_elem.html($(this).attr('data-value') + '<span class="variant-label">Custom Made</span>'+ '<span class="variant-message">' + $('.hidden-variant option').attr('data-text') + '</span>');
}
}
else{
var current_elem = $(this);
var option_value = $(this).attr('data-value');
var unavailable = false;
$('.hidden-variant option').each(function(){
if($(this).attr('value') == option_value && $(this).attr('data-available') == 'true'){
current_elem.html(option_value+ '<span class="variant-label">In Stock</span>');
unavailable = true;
}
})
if(!unavailable){
current_elem.html($(this).attr('data-value')+ '<span class="variant-label">Custom Made</span>'+ '<span class="variant-message">'+$('.hidden-variant option').attr('data-text')+'</span>');
}
}
})
// update default
if($.trim($('.prettydropdown li.selected .variant-message').html())=='') {
$('.stock-message').html("In Stock");
} else if($.trim($('.prettydropdown li.selected .variant-message').html())!='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>" + "<span class='variant-message'>" + $('.prettydropdown li.selected .variant-message').html() + "</span>");
}
},500)
}
/**
* Public Functions
*/
// Resync the menu with <select> to reflect state changes
this.refresh = function(oOptions) {
return this.each(function() {
var $select = $(this);
$select.prevAll('ul').remove();
$select.unwrap().data('loaded', false);
this.size = $select.data('size');
init(this);
});
};
return this.each(function() {
init(this);
});
};
}(jQuery));
Hi @michaelmorgan,
Please send your site and if your site is password protected, please send me the password. I will check it.
Here is a preview. I have been trying to work through a solution so the code has changed since. here is the updated code. Couple things to note is that I need the message to display for products that don't have any variants, and to basically display the variant label and message HTML of the selected dropdown. The label and message will always display in the last variant wrapper if that helps
Here is the jquery code of the whole message setup:
function stockMessage() {
var variant_message = $('.variant-wrapper').last().find('.variant-message').html();
$('.hidden-variant option').first().ready(function() {
if($(this).attr('data-available')=='true') {
$('.stock-message').html("<span class='variant-label'>" + "In Stock" + "</span>");
} else {
$('.stock-message').html("<span class='variant-label'>" + "Custom Made" + "</span>" + "<span class='variant-message'>" + variant_message + "</span>");
}
});
}
function changetext(element){
var current_option = element.attr('data-value');
document.addEventListener('variant:change', function(event) {
if($.trim($('.prettydropdown li.selected .variant-message').html())=='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>");
} else if($.trim($('.prettydropdown li.selected .variant-message').html())!='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>" + "<span class='variant-message'>" + $('.prettydropdown li.selected .variant-message').html() + "</span>");
}
}.bind(this));
setTimeout(function(){
$('.variant-input-wrap').last().find('li').each(function(){
if( $('.variant-input-wrap').eq(2).length > 0){
var first_option = $('.variant-input-wrap').eq(0).find('.selected').attr('data-value');
var second_option = $('.variant-input-wrap').eq(1).find('.selected').attr('data-value');
var current_elem = $(this);
var unavailable = false;
$('.hidden-variant option').each(function(){
if($(this).attr('value') == first_option + ' / ' + second_option + ' / ' + current_elem.attr('data-value') && $(this).attr('data-available') == 'true'){
current_elem.html(current_elem.attr('data-value') + '<span class="variant-label">In Stock</span>');
unavailable = true;
}
})
if(!unavailable){
current_elem.html($(this).attr('data-value') + '<span class="variant-label">Custom Made</span>'+ '<span class="variant-message">' + $('.hidden-variant option').attr('data-text') + '</span>');
}
}
else if( $('.variant-input-wrap').eq(1).length > 0){
var first_option = $('.variant-input-wrap').eq(0).find('.selected').attr('data-value');
var current_elem = $(this);
var unavailable = false;
$('.hidden-variant option').each(function(){
if($(this).attr('value') == first_option +' / ' + current_elem.attr('data-value') && $(this).attr('data-available') == 'true'){
current_elem.html(current_elem.attr('data-value') + '<span class="variant-label">In Stock</span>');
unavailable = true;
}
})
if(!unavailable){
current_elem.html($(this).attr('data-value') + '<span class="variant-label">Custom Made</span>'+ '<span class="variant-message">' + $('.hidden-variant option').attr('data-text') + '</span>');
}
}
else{
var current_elem = $(this);
var option_value = $(this).attr('data-value');
var unavailable = false;
$('.hidden-variant option').each(function(){
if($(this).attr('value') == option_value && $(this).attr('data-available') == 'true'){
current_elem.html(option_value+ '<span class="variant-label">In Stock</span>');
unavailable = true;
}
})
if(!unavailable){
current_elem.html($(this).attr('data-value')+ '<span class="variant-label">Custom Made</span>'+ '<span class="variant-message">'+$('.hidden-variant option').attr('data-text')+'</span>');
}
}
})
},500)
}
Here is the code of our hidden data in the product form:
<select class="hidden-variant hide no-js">
{% for variant in product.variants %}
{%- assign option_text = '' -%}
{% if product.tags contains '2 Weeks' %}
{%- assign option_text = 'Estimated production time is 2 weeks' -%}
{% elsif product.tags contains '4-6 Weeks' %}
{%- assign option_text = 'Estimated production time is 4-6 weeks' -%}
{% elsif variant.inventory_management == null %}
{% assign option_text = 'Estimated production time is 2-3 weeks' %}
{% endif %}
<option value="{{variant.title | replace:'"', '″'}}" data-available="{% if variant.inventory_quantity <= 0 %}false{% else %}true{% endif %}" data-id="{{variant.id}}" data-title="{{variant.title | replace:' / ','' | replace:'"', '″'}}" data-text="{{option_text}}">{{variant.title | replace:'"', '″'}}</option>
{% endfor %}
</select>
Thanks!
Hi @michaelmorgan,
I really don't get it, are you trying to show it for products with no variation and hide it if the product has a variant?
Is it what you want?
Hey,
I need to display it for every product. So products that have variants will have the message displayed twice. Sorry, I forgot one portion of the code that is at the top.
setTimeout(function(){
$('.variant-input-wrap').find('li').click(function() {
changetext($(this));
})
changetext($('.variant-input-wrap').eq(0).find('li').eq(0));
$('.stock-message').ready(function() {
stockMessage($(this));
})
},1000)
Hi @michaelmorgan,
Please send me the preview link, I will check it for you
Here is the link. Right now it is just displaying the first option on page load, so if someone refreshes the page after they have selected a different option with a different message, it will be wrong.
Hi @michaelmorgan,
Please change code here:
function stockMessage() {
var variant_message = $('.variant-wrapper').last().find('.variant-message').html();
$('.hidden-variant option').first().ready(function() {
if($(this).attr('data-available')=='true') {
$('.stock-message').html("<span class='variant-label'>" + "In Stock" + "</span>");
} else {
$('.stock-message').html("<span class='variant-label'>" + "Custom Made" + "</span>" + "<span class='variant-message'>" + variant_message + "</span>");
}
});
}
=>
function stockMessage() {
if($.trim($('.prettydropdown li.selected .variant-message').html())=='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>");
} else if($.trim($('.prettydropdown li.selected .variant-message').html())!='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>" + "<span class='variant-message'>" + $('.prettydropdown li.selected .variant-message').html() + "</span>");
}
}
Hope it helps!
I've tried this before and it still comes up as undefined.
Hi @michaelmorgan,
Please change all code jquery.prettydropdowns.js file:
/*!
* jQuery Pretty Dropdowns Plugin v4.17.0 by T. H. Doan (https://thdoan.github.io/pretty-dropdowns/)
*
* jQuery Pretty Dropdowns by T. H. Doan is licensed under the MIT License.
* Read a copy of the license in the LICENSE file or at https://choosealicense.com/licenses/mit/
*/
(function($) {
$.fn.prettyDropdown = function(oOptions) {
// Default options
oOptions = $.extend({
classic: true,
customClass: 'arrow',
width: null,
height: 50,
hoverIntent: -1,
multiDelimiter: '; ',
multiVerbosity: 99,
selectedMarker: '✓',
afterLoad: function(){}
}, oOptions);
oOptions.selectedMarker = '<span aria-hidden="true" class="checked"> ' + oOptions.selectedMarker + '</span>';
// Validate options
if (isNaN(oOptions.width) && !/^\d+%$/.test(oOptions.width)) oOptions.width = null;
if (isNaN(oOptions.height)) oOptions.height = 50;
else if (oOptions.height<8) oOptions.height = 8;
if (isNaN(oOptions.hoverIntent)) oOptions.hoverIntent = 200;
if (isNaN(oOptions.multiVerbosity)) oOptions.multiVerbosity = 99;
// Translatable strings
var MULTI_NONE = 'None selected',
MULTI_PREFIX = 'Selected: ',
MULTI_POSTFIX = ' selected';
// Globals
var $current,
aKeys = [
'0','1','2','3','4','5','6','7','8','9',,,,,,,,
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'
],
nCount,
nHoverIndex,
nLastIndex,
nTimer,
nTimestamp,
// Initiate pretty drop-downs
init = function(elSel) {
var $select = $(elSel),
nSize = elSel.size,
sId = elSel.name || elSel.id || '',
sLabelId;
// Exit if widget has already been initiated
if ($select.data('loaded')) return;
// Remove 'size' attribute to it doesn't affect vertical alignment
$select.data('size', nSize).removeAttr('size');
// Set <select> height to reserve space for <div> container
$select.css('display', 'none').outerHeight(oOptions.height);
nTimestamp = performance.now()*100000000000000;
// Test whether to add 'aria-labelledby'
if (elSel.id) {
// Look for <label>
var $label = $('label[for=' + elSel.id + ']');
if ($label.length) {
// Add 'id' to <label> if necessary
if ($label.attr('id') && !/^menu\d{13,}$/.test($label.attr('id'))) sLabelId = $label.attr('id');
else $label.attr('id', (sLabelId = 'menu' + nTimestamp));
}
}
nCount = 0;
var $items = $('optgroup, option', $select),
$selected = $items.filter(':selected'),
bMultiple = elSel.multiple,
// Height - 2px for borders
sHtml = '<ul' + (elSel.disabled ? '' : ' tabindex="0"') + ' role="listbox"'
+ (elSel.title ? ' title="' + elSel.title + '" aria-label="' + elSel.title + '"' : '')
+ (sLabelId ? ' aria-labelledby="' + sLabelId + '"' : '')
+ ' aria-activedescendant="item' + nTimestamp + '-1" aria-expanded="false"'
+ ' style="max-height:' + (oOptions.height-2) + 'px;margin:'
// NOTE: $select.css('margin') returns an empty string in Firefox, so we have to get
// each margin individually. See https://github.com/jquery/jquery/issues/3383
+ $select.css('margin-top') + ' '
+ $select.css('margin-right') + ' '
+ $select.css('margin-bottom') + ' '
+ $select.css('margin-left') + ';">';
if (bMultiple) {
sHtml += renderItem(null, 'selected');
$items.each(function() {
if (this.selected) {
sHtml += renderItem(this, '', true)
} else {
sHtml += renderItem(this);
}
});
} else {
if (oOptions.classic) {
$items.each(function() {
sHtml += renderItem(this);
});
} else {
sHtml += renderItem($selected[0], 'selected');
$items.filter(':not(:selected)').each(function() {
sHtml += renderItem(this);
});
}
}
sHtml += '</ul>';
$select.wrap('<div ' + (sId ? 'id="prettydropdown-' + sId + '" ' : '')
+ 'class="prettydropdown '
+ (oOptions.classic ? 'classic ' : '')
+ (elSel.disabled ? 'disabled ' : '')
+ (bMultiple ? 'multiple ' : '')
+ oOptions.customClass + ' loading"'
// NOTE: For some reason, the container height is larger by 1px if the <select> has the
// 'multiple' attribute or 'size' attribute with a value larger than 1. To fix this, we
// have to inline the height.
+ ((bMultiple || nSize>1) ? ' style="height:' + oOptions.height + 'px;"' : '')
+'></div>').before(sHtml).data('loaded', true);
var $dropdown = $select.parent().children('ul'),
nWidth = $dropdown.outerWidth(true),
nOuterWidth;
$items = $dropdown.children();
// Update default selected values for multi-select menu
if (bMultiple) updateSelected($dropdown);
else if (oOptions.classic) $('[data-value="' + $selected.val().replace(/"/g, '″') + '"]', $dropdown).addClass('selected').append(oOptions.selectedMarker);
// Calculate width if initially hidden
if ($dropdown.width()<=0) {
var $clone = $dropdown.parent().clone().css({
position: 'absolute',
top: '-100%'
});
$('body').append($clone);
nWidth = $clone.children('ul').outerWidth(true);
$('li', $clone).width(nWidth);
nOuterWidth = $clone.children('ul').outerWidth(true);
$clone.remove();
}
// Set dropdown width and event handler
// NOTE: Setting width using width(), then css() because width() only can return a float,
// which can result in a missing right border when there is a scrollbar.
$items.width(nWidth).css('width', $items.css('width'));
if (oOptions.width) {
$dropdown.parent().css('min-width', $items.css('width'));
$dropdown.css('width', '100%');
$items.css('width', '100%');
}
$items.click(function() {
var $li = $(this),
$selected = $dropdown.children('.selected');
// Ignore disabled menu
if ($dropdown.parent().hasClass('disabled')) return;
// Only update if not disabled, not a label, and a different value selected
if ($dropdown.hasClass('active') && !$li.hasClass('disabled') && !$li.hasClass('label') && $li.data('value').toString().replace(/"/g, '″')!==$selected.data('value').toString().replace(/"/g, '″')) {
// Select highlighted item
if (bMultiple) {
if ($li.children('span.checked').length) $li.children('span.checked').remove();
else $li.append(oOptions.selectedMarker);
// Sync <select> element
$dropdown.children(':not(.selected)').each(function(nIndex) {
$('optgroup, option', $select).eq(nIndex).prop('selected', $(this).children('span.checked').length>0);
});
// Update selected values for multi-select menu
updateSelected($dropdown);
} else {
$selected.removeClass('selected').children('span.checked').remove();
$li.addClass('selected').append(oOptions.selectedMarker);
if (!oOptions.classic) $dropdown.prepend($li);
$dropdown.removeClass('reverse').attr('aria-activedescendant', $li.attr('id'));
if ($selected.data('group') && !oOptions.classic) $dropdown.children('.label').filter(function() {
return $(this).text()===$selected.data('group');
}).after($selected);
// Sync <select> element
$('optgroup, option', $select).filter(function() {
// <option>: this.value = this.text, $li.data('value') = $li.contents()
// <option value="">: this.value = "", $li.data('value') = undefined
return (this.value.replace(/"/g, '″')+'|'+this.text.replace(/"/g, '″'))===($li.data('value')||'')+'|'+$li.contents().filter(function() {
// Filter out selected marker
return this.nodeType===3;
}).text();
}).prop('selected', true);
}
$select.get(0).dispatchEvent(new Event('change'))
}
if ($li.hasClass('selected') || !bMultiple) {
$dropdown.toggleClass('active');
$dropdown.attr('aria-expanded', $dropdown.hasClass('active'));
}
// Try to keep drop-down menu within viewport
if ($dropdown.hasClass('active')) {
// Close any other open menus
if ($('.prettydropdown > ul.active').length>1) {
resetDropdown($('.prettydropdown > ul.active').not($dropdown));
$('.prettydropdown > ul.active').not($dropdown).removeClass('active');
}
var nWinHeight = window.innerHeight,
nMaxHeight,
nOffsetTop = $dropdown.offset().top,
nScrollTop = $(document).scrollTop(),
nDropdownHeight = $dropdown.outerHeight();
if (nSize) {
nMaxHeight = nSize*(oOptions.height-2);
if (nMaxHeight<nDropdownHeight-2) nDropdownHeight = nMaxHeight+2;
}
var nDropdownBottom = nOffsetTop-nScrollTop+nDropdownHeight;
if (nDropdownBottom>nWinHeight) {
// Expand to direction that has the most space
if (nOffsetTop-nScrollTop>nWinHeight-(nOffsetTop-nScrollTop+oOptions.height)) {
$dropdown.addClass('reverse');
if (!oOptions.classic) $dropdown.append($selected);
if (nOffsetTop-nScrollTop+oOptions.height<nDropdownHeight) {
$dropdown.outerHeight(nOffsetTop-nScrollTop+oOptions.height);
// Ensure the selected item is in view
$dropdown.scrollTop(nDropdownHeight);
}
} else {
$dropdown.height($dropdown.height()-(nDropdownBottom-nWinHeight));
}
}
if (nMaxHeight && nMaxHeight<$dropdown.height()) $dropdown.css('height', nMaxHeight + 'px');
// Ensure the selected item is in view
if (oOptions.classic) $dropdown.scrollTop($selected.index()*(oOptions.height-2));
} else {
$dropdown.data('clicked', true);
resetDropdown($dropdown[0]);
}
});
$dropdown.on({
focusin: function() {
// Unregister any existing handlers first to prevent duplicate firings
$(window).off('keydown', handleKeypress).on('keydown', handleKeypress);
},
focusout: function() {
$(window).off('keydown', handleKeypress);
},
mouseenter: function() {
$dropdown.data('hover', true);
},
mouseleave: resetDropdown,
mousemove: hoverDropdownItem
});
if (oOptions.hoverIntent<0) {
$(document).click(function(e) {
if ($dropdown.data('hover') && !$dropdown[0].contains(e.target)) resetDropdown($dropdown[0]);
});
}
// Put focus on menu when user clicks on label
if (sLabelId) $('#' + sLabelId).off('click', handleFocus).click(handleFocus);
// Done with everything!
$dropdown.parent().width(oOptions.width||nOuterWidth||$dropdown.outerWidth(true)).removeClass('loading');
oOptions.afterLoad();
},
// Manage widget focusing
handleFocus = function(e) {
$('ul[aria-labelledby=' + e.target.id + ']').focus();
},
// Manage keyboard navigation
handleKeypress = function(e) {
var $dropdown = $('.prettydropdown > ul.active, .prettydropdown > ul:focus');
if (!$dropdown.length) return;
if (e.which===9) { // Tab
resetDropdown($dropdown[0]);
return;
} else {
// Intercept non-Tab keys only
e.preventDefault();
e.stopPropagation();
}
var $items = $dropdown.children(),
bOpen = $dropdown.hasClass('active'),
nItemsHeight = $dropdown.height()/(oOptions.height-2),
nItemsPerPage = nItemsHeight%1<0.5 ? Math.floor(nItemsHeight) : Math.ceil(nItemsHeight),
sKey;
nHoverIndex = Math.max(0, $dropdown.children('.hover').index());
nLastIndex = $items.length-1;
$current = $items.eq(nHoverIndex);
$dropdown.data('lastKeypress', +new Date());
switch (e.which) {
case 13: // Enter
if (!bOpen) {
$current = $items.filter('.selected');
toggleHover($current, 1);
}
$current.click();
break;
case 27: // Esc
if (bOpen) resetDropdown($dropdown[0]);
break;
case 32: // Space
if (bOpen) {
sKey = ' ';
} else {
$current = $items.filter('.selected');
toggleHover($current, 1);
$current.click();
}
break;
case 33: // Page Up
if (bOpen) {
toggleHover($current, 0);
toggleHover($items.eq(Math.max(nHoverIndex-nItemsPerPage-1, 0)), 1);
}
break;
case 34: // Page Down
if (bOpen) {
toggleHover($current, 0);
toggleHover($items.eq(Math.min(nHoverIndex+nItemsPerPage-1, nLastIndex)), 1);
}
break;
case 35: // End
if (bOpen) {
toggleHover($current, 0);
toggleHover($items.eq(nLastIndex), 1);
}
break;
case 36: // Home
if (bOpen) {
toggleHover($current, 0);
toggleHover($items.eq(0), 1);
}
break;
case 38: // Up
if (bOpen) {
toggleHover($current, 0);
// If not already key-navigated or first item is selected, cycle to the last item; or
// else select the previous item
toggleHover(nHoverIndex ? $items.eq(nHoverIndex-1) : $items.eq(nLastIndex), 1);
}
break;
case 40: // Down
if (bOpen) {
toggleHover($current, 0);
// If last item is selected, cycle to the first item; or else select the next item
toggleHover(nHoverIndex===nLastIndex ? $items.eq(0) : $items.eq(nHoverIndex+1), 1);
}
break;
default:
if (bOpen) sKey = aKeys[e.which-48];
}
if (sKey) { // Alphanumeric key pressed
clearTimeout(nTimer);
$dropdown.data('keysPressed', $dropdown.data('keysPressed')===undefined ? sKey : $dropdown.data('keysPressed') + sKey);
nTimer = setTimeout(function() {
$dropdown.removeData('keysPressed');
// NOTE: Windows keyboard repeat delay is 250-1000 ms. See
// https://technet.microsoft.com/en-us/library/cc978658.aspx
}, 300);
// Build index of matches
var aMatches = [],
nCurrentIndex = $current.index();
$items.each(function(nIndex) {
if ($(this).text().toLowerCase().indexOf($dropdown.data('keysPressed'))===0) aMatches.push(nIndex);
});
if (aMatches.length) {
// Cycle through items matching key(s) pressed
for (var i=0; i<aMatches.length; ++i) {
if (aMatches[i]>nCurrentIndex) {
toggleHover($items, 0);
toggleHover($items.eq(aMatches[i]), 1);
break;
}
if (i===aMatches.length-1) {
toggleHover($items, 0);
toggleHover($items.eq(aMatches[0]), 1);
}
}
}
}
},
// Highlight menu item
hoverDropdownItem = function(e) {
var $dropdown = $(e.currentTarget);
if (e.target.nodeName!=='LI' || !$dropdown.hasClass('active') || new Date()-$dropdown.data('lastKeypress')<200) return;
toggleHover($dropdown.children(), 0, 1);
toggleHover($(e.target), 1, 1);
},
// Construct menu item
// elOpt is null for first item in multi-select menus
renderItem = function(elOpt, sClass, bSelected) {
var sGroup = '',
sText = '',
sTitle;
sClass = sClass || '';
if (elOpt) {
switch (elOpt.nodeName) {
case 'OPTION':
if (elOpt.parentNode.nodeName==='OPTGROUP') sGroup = elOpt.parentNode.getAttribute('label');
sText = (elOpt.getAttribute('data-prefix') || '') + elOpt.text + (elOpt.getAttribute('data-suffix') || '');
break;
case 'OPTGROUP':
sClass += ' label';
sText = (elOpt.getAttribute('data-prefix') || '') + elOpt.getAttribute('label') + (elOpt.getAttribute('data-suffix') || '');
break;
}
// if (elOpt.disabled || (sGroup && elOpt.parentNode.disabled)) sClass += ' disabled';
sTitle = elOpt.title;
if (sGroup && !sTitle) sTitle = elOpt.parentNode.title;
}
++nCount;
return '<li id="item' + nTimestamp + '-' + nCount + '"'
+ (sGroup ? ' data-group="' + sGroup + '"' : '')
+ (elOpt && (elOpt.value||oOptions.classic) ? ' data-value="' + elOpt.value.replace(/"/g, '″') + '"' : '')
+ (elOpt && elOpt.nodeName==='OPTION' ? ' role="option"' : '')
+ (sTitle ? ' title="' + sTitle + '" aria-label="' + sTitle + '"' : '')
+ (sClass ? ' class="' + $.trim(sClass) + '"' : '')
+ ((oOptions.height!==50) ? ' style="height:' + (oOptions.height-2)
+ 'px;line-height:' + (oOptions.height-4) + 'px;"' : '') + '>' + sText
+ ((bSelected || sClass==='selected') ? oOptions.selectedMarker : '') + '</li>';
},
// Reset menu state
// @param o Event or Element object
resetDropdown = function(o) {
if (oOptions.hoverIntent<0 && o.type==='mouseleave') return;
var $dropdown = $(o.currentTarget||o);
$dropdown.data('hover', false);
clearTimeout(nTimer);
nTimer = setTimeout(function() {
if ($dropdown.data('hover')) return;
if ($dropdown.hasClass('reverse') && !oOptions.classic) $dropdown.prepend($dropdown.children(':last-child'));
$dropdown.removeClass('active reverse').removeData('clicked').attr('aria-expanded', 'false').css('height', '');
$dropdown.children().removeClass('hover nohover');
// Update focus for NVDA screen readers
$dropdown.attr('aria-activedescendant', $dropdown.children('.selected').attr('id'));
}, (o.type==='mouseleave' && !$dropdown.data('clicked')) ? oOptions.hoverIntent : 0);
},
// Set menu item hover state
// bNoScroll set on hoverDropdownItem()
toggleHover = function($li, bOn, bNoScroll) {
if (bOn) {
var $dropdown = $li.parent();
$li.removeClass('nohover').addClass('hover');
// Update focus for NVDA screen readers
$dropdown.attr('aria-activedescendant', $li.attr('id'));
if ($li.length===1 && $current && !bNoScroll) {
// Ensure items are always in view
var nDropdownHeight = $dropdown.outerHeight(),
nItemOffset = $li.offset().top-$dropdown.offset().top-1; // -1px for top border
if ($li.index()===0) {
$dropdown.scrollTop(0);
} else if ($li.index()===nLastIndex) {
$dropdown.scrollTop($dropdown.children().length*oOptions.height);
} else {
if (nItemOffset+oOptions.height>nDropdownHeight) $dropdown.scrollTop($dropdown.scrollTop()+oOptions.height+nItemOffset-nDropdownHeight);
else if (nItemOffset<0) $dropdown.scrollTop($dropdown.scrollTop()+nItemOffset);
}
}
} else {
$li.removeClass('hover').addClass('nohover');
}
},
// Update selected values for multi-select menu
updateSelected = function($dropdown) {
var $select = $dropdown.parent().children('select'),
aSelected = $('option', $select).map(function() {
if (this.selected) return this.text;
}).get(),
sSelected;
if (oOptions.multiVerbosity>=aSelected.length) sSelected = aSelected.join(oOptions.multiDelimiter) || MULTI_NONE;
else sSelected = aSelected.length + '/' + $('option', $select).length + MULTI_POSTFIX;
if (sSelected) {
var sTitle = ($select.attr('title') ? $select.attr('title') : '') + (aSelected.length ? '\n' + MULTI_PREFIX + aSelected.join(oOptions.multiDelimiter) : '');
$dropdown.children('.selected').text(sSelected);
$dropdown.attr({
'title': sTitle,
'aria-label': sTitle
});
} else {
$dropdown.children('.selected').empty();
$dropdown.attr({
'title': $select.attr('title'),
'aria-label': $select.attr('title')
});
}
};
setTimeout(function(){
$('.variant-input-wrap').find('li').click(function() {
changetext($(this));
})
changetext($('.variant-input-wrap').eq(0).find('li').eq(0));
$('.stock-message').ready(function() {
stockMessage($(this));
})
},1000)
function stockMessage() {
// var variant_message = $('.variant-wrapper').last().find('.variant-message').html();
// $('.hidden-variant option').first().ready(function() {
// if($(this).attr('data-available')=='true') {
// $('.stock-message').html("<span class='variant-label'>" + "In Stock" + "</span>");
// } else {
// $('.stock-message').html("<span class='variant-label'>" + "Custom Made" + "</span>" + "<span class='variant-message'>" + variant_message + "</span>");
// }
// });
}
function changetext(element){
var current_option = element.attr('data-value');
document.addEventListener('variant:change', function(event) {
if($.trim($('.prettydropdown li.selected .variant-message').html())=='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>");
} else if($.trim($('.prettydropdown li.selected .variant-message').html())!='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>" + "<span class='variant-message'>" + $('.prettydropdown li.selected .variant-message').html() + "</span>");
}
}.bind(this));
setTimeout(function(){
$('.variant-input-wrap').last().find('li').each(function(){
if( $('.variant-input-wrap').eq(2).length > 0){
var first_option = $('.variant-input-wrap').eq(0).find('.selected').attr('data-value');
var second_option = $('.variant-input-wrap').eq(1).find('.selected').attr('data-value');
var current_elem = $(this);
var unavailable = false;
$('.hidden-variant option').each(function(){
if($(this).attr('value') == first_option + ' / ' + second_option + ' / ' + current_elem.attr('data-value') && $(this).attr('data-available') == 'true'){
current_elem.html(current_elem.attr('data-value') + '<span class="variant-label">In Stock</span>');
unavailable = true;
}
})
if(!unavailable){
current_elem.html($(this).attr('data-value') + '<span class="variant-label">Custom Made</span>'+ '<span class="variant-message">' + $('.hidden-variant option').attr('data-text') + '</span>');
}
}
else if( $('.variant-input-wrap').eq(1).length > 0){
var first_option = $('.variant-input-wrap').eq(0).find('.selected').attr('data-value');
var current_elem = $(this);
var unavailable = false;
$('.hidden-variant option').each(function(){
if($(this).attr('value') == first_option +' / ' + current_elem.attr('data-value') && $(this).attr('data-available') == 'true'){
current_elem.html(current_elem.attr('data-value') + '<span class="variant-label">In Stock</span>');
unavailable = true;
}
})
if(!unavailable){
current_elem.html($(this).attr('data-value') + '<span class="variant-label">Custom Made</span>'+ '<span class="variant-message">' + $('.hidden-variant option').attr('data-text') + '</span>');
}
}
else{
var current_elem = $(this);
var option_value = $(this).attr('data-value');
var unavailable = false;
$('.hidden-variant option').each(function(){
if($(this).attr('value') == option_value && $(this).attr('data-available') == 'true'){
current_elem.html(option_value+ '<span class="variant-label">In Stock</span>');
unavailable = true;
}
})
if(!unavailable){
current_elem.html($(this).attr('data-value')+ '<span class="variant-label">Custom Made</span>'+ '<span class="variant-message">'+$('.hidden-variant option').attr('data-text')+'</span>');
}
}
})
// update default
if($.trim($('.prettydropdown li.selected .variant-message').html())=='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>");
} else if($.trim($('.prettydropdown li.selected .variant-message').html())!='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>" + "<span class='variant-message'>" + $('.prettydropdown li.selected .variant-message').html() + "</span>");
}
},500)
}
/**
* Public Functions
*/
// Resync the menu with <select> to reflect state changes
this.refresh = function(oOptions) {
return this.each(function() {
var $select = $(this);
$select.prevAll('ul').remove();
$select.unwrap().data('loaded', false);
this.size = $select.data('size');
init(this);
});
};
return this.each(function() {
init(this);
});
};
}(jQuery));
This works perfectly for products with multiple variants. Only issue now are products with no variants like this one display as 'undefined'
This is an accepted solution.
Hi @michaelmorgan,
Please change all code:
/*!
* jQuery Pretty Dropdowns Plugin v4.17.0 by T. H. Doan (https://thdoan.github.io/pretty-dropdowns/)
*
* jQuery Pretty Dropdowns by T. H. Doan is licensed under the MIT License.
* Read a copy of the license in the LICENSE file or at https://choosealicense.com/licenses/mit/
*/
(function($) {
$.fn.prettyDropdown = function(oOptions) {
// Default options
oOptions = $.extend({
classic: true,
customClass: 'arrow',
width: null,
height: 50,
hoverIntent: -1,
multiDelimiter: '; ',
multiVerbosity: 99,
selectedMarker: '✓',
afterLoad: function(){}
}, oOptions);
oOptions.selectedMarker = '<span aria-hidden="true" class="checked"> ' + oOptions.selectedMarker + '</span>';
// Validate options
if (isNaN(oOptions.width) && !/^\d+%$/.test(oOptions.width)) oOptions.width = null;
if (isNaN(oOptions.height)) oOptions.height = 50;
else if (oOptions.height<8) oOptions.height = 8;
if (isNaN(oOptions.hoverIntent)) oOptions.hoverIntent = 200;
if (isNaN(oOptions.multiVerbosity)) oOptions.multiVerbosity = 99;
// Translatable strings
var MULTI_NONE = 'None selected',
MULTI_PREFIX = 'Selected: ',
MULTI_POSTFIX = ' selected';
// Globals
var $current,
aKeys = [
'0','1','2','3','4','5','6','7','8','9',,,,,,,,
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'
],
nCount,
nHoverIndex,
nLastIndex,
nTimer,
nTimestamp,
// Initiate pretty drop-downs
init = function(elSel) {
var $select = $(elSel),
nSize = elSel.size,
sId = elSel.name || elSel.id || '',
sLabelId;
// Exit if widget has already been initiated
if ($select.data('loaded')) return;
// Remove 'size' attribute to it doesn't affect vertical alignment
$select.data('size', nSize).removeAttr('size');
// Set <select> height to reserve space for <div> container
$select.css('display', 'none').outerHeight(oOptions.height);
nTimestamp = performance.now()*100000000000000;
// Test whether to add 'aria-labelledby'
if (elSel.id) {
// Look for <label>
var $label = $('label[for=' + elSel.id + ']');
if ($label.length) {
// Add 'id' to <label> if necessary
if ($label.attr('id') && !/^menu\d{13,}$/.test($label.attr('id'))) sLabelId = $label.attr('id');
else $label.attr('id', (sLabelId = 'menu' + nTimestamp));
}
}
nCount = 0;
var $items = $('optgroup, option', $select),
$selected = $items.filter(':selected'),
bMultiple = elSel.multiple,
// Height - 2px for borders
sHtml = '<ul' + (elSel.disabled ? '' : ' tabindex="0"') + ' role="listbox"'
+ (elSel.title ? ' title="' + elSel.title + '" aria-label="' + elSel.title + '"' : '')
+ (sLabelId ? ' aria-labelledby="' + sLabelId + '"' : '')
+ ' aria-activedescendant="item' + nTimestamp + '-1" aria-expanded="false"'
+ ' style="max-height:' + (oOptions.height-2) + 'px;margin:'
// NOTE: $select.css('margin') returns an empty string in Firefox, so we have to get
// each margin individually. See https://github.com/jquery/jquery/issues/3383
+ $select.css('margin-top') + ' '
+ $select.css('margin-right') + ' '
+ $select.css('margin-bottom') + ' '
+ $select.css('margin-left') + ';">';
if (bMultiple) {
sHtml += renderItem(null, 'selected');
$items.each(function() {
if (this.selected) {
sHtml += renderItem(this, '', true)
} else {
sHtml += renderItem(this);
}
});
} else {
if (oOptions.classic) {
$items.each(function() {
sHtml += renderItem(this);
});
} else {
sHtml += renderItem($selected[0], 'selected');
$items.filter(':not(:selected)').each(function() {
sHtml += renderItem(this);
});
}
}
sHtml += '</ul>';
$select.wrap('<div ' + (sId ? 'id="prettydropdown-' + sId + '" ' : '')
+ 'class="prettydropdown '
+ (oOptions.classic ? 'classic ' : '')
+ (elSel.disabled ? 'disabled ' : '')
+ (bMultiple ? 'multiple ' : '')
+ oOptions.customClass + ' loading"'
// NOTE: For some reason, the container height is larger by 1px if the <select> has the
// 'multiple' attribute or 'size' attribute with a value larger than 1. To fix this, we
// have to inline the height.
+ ((bMultiple || nSize>1) ? ' style="height:' + oOptions.height + 'px;"' : '')
+'></div>').before(sHtml).data('loaded', true);
var $dropdown = $select.parent().children('ul'),
nWidth = $dropdown.outerWidth(true),
nOuterWidth;
$items = $dropdown.children();
// Update default selected values for multi-select menu
if (bMultiple) updateSelected($dropdown);
else if (oOptions.classic) $('[data-value="' + $selected.val().replace(/"/g, '″') + '"]', $dropdown).addClass('selected').append(oOptions.selectedMarker);
// Calculate width if initially hidden
if ($dropdown.width()<=0) {
var $clone = $dropdown.parent().clone().css({
position: 'absolute',
top: '-100%'
});
$('body').append($clone);
nWidth = $clone.children('ul').outerWidth(true);
$('li', $clone).width(nWidth);
nOuterWidth = $clone.children('ul').outerWidth(true);
$clone.remove();
}
// Set dropdown width and event handler
// NOTE: Setting width using width(), then css() because width() only can return a float,
// which can result in a missing right border when there is a scrollbar.
$items.width(nWidth).css('width', $items.css('width'));
if (oOptions.width) {
$dropdown.parent().css('min-width', $items.css('width'));
$dropdown.css('width', '100%');
$items.css('width', '100%');
}
$items.click(function() {
var $li = $(this),
$selected = $dropdown.children('.selected');
// Ignore disabled menu
if ($dropdown.parent().hasClass('disabled')) return;
// Only update if not disabled, not a label, and a different value selected
if ($dropdown.hasClass('active') && !$li.hasClass('disabled') && !$li.hasClass('label') && $li.data('value').toString().replace(/"/g, '″')!==$selected.data('value').toString().replace(/"/g, '″')) {
// Select highlighted item
if (bMultiple) {
if ($li.children('span.checked').length) $li.children('span.checked').remove();
else $li.append(oOptions.selectedMarker);
// Sync <select> element
$dropdown.children(':not(.selected)').each(function(nIndex) {
$('optgroup, option', $select).eq(nIndex).prop('selected', $(this).children('span.checked').length>0);
});
// Update selected values for multi-select menu
updateSelected($dropdown);
} else {
$selected.removeClass('selected').children('span.checked').remove();
$li.addClass('selected').append(oOptions.selectedMarker);
if (!oOptions.classic) $dropdown.prepend($li);
$dropdown.removeClass('reverse').attr('aria-activedescendant', $li.attr('id'));
if ($selected.data('group') && !oOptions.classic) $dropdown.children('.label').filter(function() {
return $(this).text()===$selected.data('group');
}).after($selected);
// Sync <select> element
$('optgroup, option', $select).filter(function() {
// <option>: this.value = this.text, $li.data('value') = $li.contents()
// <option value="">: this.value = "", $li.data('value') = undefined
return (this.value.replace(/"/g, '″')+'|'+this.text.replace(/"/g, '″'))===($li.data('value')||'')+'|'+$li.contents().filter(function() {
// Filter out selected marker
return this.nodeType===3;
}).text();
}).prop('selected', true);
}
$select.get(0).dispatchEvent(new Event('change'))
}
if ($li.hasClass('selected') || !bMultiple) {
$dropdown.toggleClass('active');
$dropdown.attr('aria-expanded', $dropdown.hasClass('active'));
}
// Try to keep drop-down menu within viewport
if ($dropdown.hasClass('active')) {
// Close any other open menus
if ($('.prettydropdown > ul.active').length>1) {
resetDropdown($('.prettydropdown > ul.active').not($dropdown));
$('.prettydropdown > ul.active').not($dropdown).removeClass('active');
}
var nWinHeight = window.innerHeight,
nMaxHeight,
nOffsetTop = $dropdown.offset().top,
nScrollTop = $(document).scrollTop(),
nDropdownHeight = $dropdown.outerHeight();
if (nSize) {
nMaxHeight = nSize*(oOptions.height-2);
if (nMaxHeight<nDropdownHeight-2) nDropdownHeight = nMaxHeight+2;
}
var nDropdownBottom = nOffsetTop-nScrollTop+nDropdownHeight;
if (nDropdownBottom>nWinHeight) {
// Expand to direction that has the most space
if (nOffsetTop-nScrollTop>nWinHeight-(nOffsetTop-nScrollTop+oOptions.height)) {
$dropdown.addClass('reverse');
if (!oOptions.classic) $dropdown.append($selected);
if (nOffsetTop-nScrollTop+oOptions.height<nDropdownHeight) {
$dropdown.outerHeight(nOffsetTop-nScrollTop+oOptions.height);
// Ensure the selected item is in view
$dropdown.scrollTop(nDropdownHeight);
}
} else {
$dropdown.height($dropdown.height()-(nDropdownBottom-nWinHeight));
}
}
if (nMaxHeight && nMaxHeight<$dropdown.height()) $dropdown.css('height', nMaxHeight + 'px');
// Ensure the selected item is in view
if (oOptions.classic) $dropdown.scrollTop($selected.index()*(oOptions.height-2));
} else {
$dropdown.data('clicked', true);
resetDropdown($dropdown[0]);
}
});
$dropdown.on({
focusin: function() {
// Unregister any existing handlers first to prevent duplicate firings
$(window).off('keydown', handleKeypress).on('keydown', handleKeypress);
},
focusout: function() {
$(window).off('keydown', handleKeypress);
},
mouseenter: function() {
$dropdown.data('hover', true);
},
mouseleave: resetDropdown,
mousemove: hoverDropdownItem
});
if (oOptions.hoverIntent<0) {
$(document).click(function(e) {
if ($dropdown.data('hover') && !$dropdown[0].contains(e.target)) resetDropdown($dropdown[0]);
});
}
// Put focus on menu when user clicks on label
if (sLabelId) $('#' + sLabelId).off('click', handleFocus).click(handleFocus);
// Done with everything!
$dropdown.parent().width(oOptions.width||nOuterWidth||$dropdown.outerWidth(true)).removeClass('loading');
oOptions.afterLoad();
},
// Manage widget focusing
handleFocus = function(e) {
$('ul[aria-labelledby=' + e.target.id + ']').focus();
},
// Manage keyboard navigation
handleKeypress = function(e) {
var $dropdown = $('.prettydropdown > ul.active, .prettydropdown > ul:focus');
if (!$dropdown.length) return;
if (e.which===9) { // Tab
resetDropdown($dropdown[0]);
return;
} else {
// Intercept non-Tab keys only
e.preventDefault();
e.stopPropagation();
}
var $items = $dropdown.children(),
bOpen = $dropdown.hasClass('active'),
nItemsHeight = $dropdown.height()/(oOptions.height-2),
nItemsPerPage = nItemsHeight%1<0.5 ? Math.floor(nItemsHeight) : Math.ceil(nItemsHeight),
sKey;
nHoverIndex = Math.max(0, $dropdown.children('.hover').index());
nLastIndex = $items.length-1;
$current = $items.eq(nHoverIndex);
$dropdown.data('lastKeypress', +new Date());
switch (e.which) {
case 13: // Enter
if (!bOpen) {
$current = $items.filter('.selected');
toggleHover($current, 1);
}
$current.click();
break;
case 27: // Esc
if (bOpen) resetDropdown($dropdown[0]);
break;
case 32: // Space
if (bOpen) {
sKey = ' ';
} else {
$current = $items.filter('.selected');
toggleHover($current, 1);
$current.click();
}
break;
case 33: // Page Up
if (bOpen) {
toggleHover($current, 0);
toggleHover($items.eq(Math.max(nHoverIndex-nItemsPerPage-1, 0)), 1);
}
break;
case 34: // Page Down
if (bOpen) {
toggleHover($current, 0);
toggleHover($items.eq(Math.min(nHoverIndex+nItemsPerPage-1, nLastIndex)), 1);
}
break;
case 35: // End
if (bOpen) {
toggleHover($current, 0);
toggleHover($items.eq(nLastIndex), 1);
}
break;
case 36: // Home
if (bOpen) {
toggleHover($current, 0);
toggleHover($items.eq(0), 1);
}
break;
case 38: // Up
if (bOpen) {
toggleHover($current, 0);
// If not already key-navigated or first item is selected, cycle to the last item; or
// else select the previous item
toggleHover(nHoverIndex ? $items.eq(nHoverIndex-1) : $items.eq(nLastIndex), 1);
}
break;
case 40: // Down
if (bOpen) {
toggleHover($current, 0);
// If last item is selected, cycle to the first item; or else select the next item
toggleHover(nHoverIndex===nLastIndex ? $items.eq(0) : $items.eq(nHoverIndex+1), 1);
}
break;
default:
if (bOpen) sKey = aKeys[e.which-48];
}
if (sKey) { // Alphanumeric key pressed
clearTimeout(nTimer);
$dropdown.data('keysPressed', $dropdown.data('keysPressed')===undefined ? sKey : $dropdown.data('keysPressed') + sKey);
nTimer = setTimeout(function() {
$dropdown.removeData('keysPressed');
// NOTE: Windows keyboard repeat delay is 250-1000 ms. See
// https://technet.microsoft.com/en-us/library/cc978658.aspx
}, 300);
// Build index of matches
var aMatches = [],
nCurrentIndex = $current.index();
$items.each(function(nIndex) {
if ($(this).text().toLowerCase().indexOf($dropdown.data('keysPressed'))===0) aMatches.push(nIndex);
});
if (aMatches.length) {
// Cycle through items matching key(s) pressed
for (var i=0; i<aMatches.length; ++i) {
if (aMatches[i]>nCurrentIndex) {
toggleHover($items, 0);
toggleHover($items.eq(aMatches[i]), 1);
break;
}
if (i===aMatches.length-1) {
toggleHover($items, 0);
toggleHover($items.eq(aMatches[0]), 1);
}
}
}
}
},
// Highlight menu item
hoverDropdownItem = function(e) {
var $dropdown = $(e.currentTarget);
if (e.target.nodeName!=='LI' || !$dropdown.hasClass('active') || new Date()-$dropdown.data('lastKeypress')<200) return;
toggleHover($dropdown.children(), 0, 1);
toggleHover($(e.target), 1, 1);
},
// Construct menu item
// elOpt is null for first item in multi-select menus
renderItem = function(elOpt, sClass, bSelected) {
var sGroup = '',
sText = '',
sTitle;
sClass = sClass || '';
if (elOpt) {
switch (elOpt.nodeName) {
case 'OPTION':
if (elOpt.parentNode.nodeName==='OPTGROUP') sGroup = elOpt.parentNode.getAttribute('label');
sText = (elOpt.getAttribute('data-prefix') || '') + elOpt.text + (elOpt.getAttribute('data-suffix') || '');
break;
case 'OPTGROUP':
sClass += ' label';
sText = (elOpt.getAttribute('data-prefix') || '') + elOpt.getAttribute('label') + (elOpt.getAttribute('data-suffix') || '');
break;
}
// if (elOpt.disabled || (sGroup && elOpt.parentNode.disabled)) sClass += ' disabled';
sTitle = elOpt.title;
if (sGroup && !sTitle) sTitle = elOpt.parentNode.title;
}
++nCount;
return '<li id="item' + nTimestamp + '-' + nCount + '"'
+ (sGroup ? ' data-group="' + sGroup + '"' : '')
+ (elOpt && (elOpt.value||oOptions.classic) ? ' data-value="' + elOpt.value.replace(/"/g, '″') + '"' : '')
+ (elOpt && elOpt.nodeName==='OPTION' ? ' role="option"' : '')
+ (sTitle ? ' title="' + sTitle + '" aria-label="' + sTitle + '"' : '')
+ (sClass ? ' class="' + $.trim(sClass) + '"' : '')
+ ((oOptions.height!==50) ? ' style="height:' + (oOptions.height-2)
+ 'px;line-height:' + (oOptions.height-4) + 'px;"' : '') + '>' + sText
+ ((bSelected || sClass==='selected') ? oOptions.selectedMarker : '') + '</li>';
},
// Reset menu state
// @param o Event or Element object
resetDropdown = function(o) {
if (oOptions.hoverIntent<0 && o.type==='mouseleave') return;
var $dropdown = $(o.currentTarget||o);
$dropdown.data('hover', false);
clearTimeout(nTimer);
nTimer = setTimeout(function() {
if ($dropdown.data('hover')) return;
if ($dropdown.hasClass('reverse') && !oOptions.classic) $dropdown.prepend($dropdown.children(':last-child'));
$dropdown.removeClass('active reverse').removeData('clicked').attr('aria-expanded', 'false').css('height', '');
$dropdown.children().removeClass('hover nohover');
// Update focus for NVDA screen readers
$dropdown.attr('aria-activedescendant', $dropdown.children('.selected').attr('id'));
}, (o.type==='mouseleave' && !$dropdown.data('clicked')) ? oOptions.hoverIntent : 0);
},
// Set menu item hover state
// bNoScroll set on hoverDropdownItem()
toggleHover = function($li, bOn, bNoScroll) {
if (bOn) {
var $dropdown = $li.parent();
$li.removeClass('nohover').addClass('hover');
// Update focus for NVDA screen readers
$dropdown.attr('aria-activedescendant', $li.attr('id'));
if ($li.length===1 && $current && !bNoScroll) {
// Ensure items are always in view
var nDropdownHeight = $dropdown.outerHeight(),
nItemOffset = $li.offset().top-$dropdown.offset().top-1; // -1px for top border
if ($li.index()===0) {
$dropdown.scrollTop(0);
} else if ($li.index()===nLastIndex) {
$dropdown.scrollTop($dropdown.children().length*oOptions.height);
} else {
if (nItemOffset+oOptions.height>nDropdownHeight) $dropdown.scrollTop($dropdown.scrollTop()+oOptions.height+nItemOffset-nDropdownHeight);
else if (nItemOffset<0) $dropdown.scrollTop($dropdown.scrollTop()+nItemOffset);
}
}
} else {
$li.removeClass('hover').addClass('nohover');
}
},
// Update selected values for multi-select menu
updateSelected = function($dropdown) {
var $select = $dropdown.parent().children('select'),
aSelected = $('option', $select).map(function() {
if (this.selected) return this.text;
}).get(),
sSelected;
if (oOptions.multiVerbosity>=aSelected.length) sSelected = aSelected.join(oOptions.multiDelimiter) || MULTI_NONE;
else sSelected = aSelected.length + '/' + $('option', $select).length + MULTI_POSTFIX;
if (sSelected) {
var sTitle = ($select.attr('title') ? $select.attr('title') : '') + (aSelected.length ? '\n' + MULTI_PREFIX + aSelected.join(oOptions.multiDelimiter) : '');
$dropdown.children('.selected').text(sSelected);
$dropdown.attr({
'title': sTitle,
'aria-label': sTitle
});
} else {
$dropdown.children('.selected').empty();
$dropdown.attr({
'title': $select.attr('title'),
'aria-label': $select.attr('title')
});
}
};
setTimeout(function(){
$('.variant-input-wrap').find('li').click(function() {
changetext($(this));
})
changetext($('.variant-input-wrap').eq(0).find('li').eq(0));
$('.stock-message').ready(function() {
stockMessage($(this));
})
},1000)
function stockMessage() {
// var variant_message = $('.variant-wrapper').last().find('.variant-message').html();
// $('.hidden-variant option').first().ready(function() {
// if($(this).attr('data-available')=='true') {
// $('.stock-message').html("<span class='variant-label'>" + "In Stock" + "</span>");
// } else {
// $('.stock-message').html("<span class='variant-label'>" + "Custom Made" + "</span>" + "<span class='variant-message'>" + variant_message + "</span>");
// }
// });
}
function changetext(element){
var current_option = element.attr('data-value');
document.addEventListener('variant:change', function(event) {
if($.trim($('.prettydropdown li.selected .variant-message').html())=='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>");
} else if($.trim($('.prettydropdown li.selected .variant-message').html())!='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>" + "<span class='variant-message'>" + $('.prettydropdown li.selected .variant-message').html() + "</span>");
}
}.bind(this));
setTimeout(function(){
$('.variant-input-wrap').last().find('li').each(function(){
if( $('.variant-input-wrap').eq(2).length > 0){
var first_option = $('.variant-input-wrap').eq(0).find('.selected').attr('data-value');
var second_option = $('.variant-input-wrap').eq(1).find('.selected').attr('data-value');
var current_elem = $(this);
var unavailable = false;
$('.hidden-variant option').each(function(){
if($(this).attr('value') == first_option + ' / ' + second_option + ' / ' + current_elem.attr('data-value') && $(this).attr('data-available') == 'true'){
current_elem.html(current_elem.attr('data-value') + '<span class="variant-label">In Stock</span>');
unavailable = true;
}
})
if(!unavailable){
current_elem.html($(this).attr('data-value') + '<span class="variant-label">Custom Made</span>'+ '<span class="variant-message">' + $('.hidden-variant option').attr('data-text') + '</span>');
}
}
else if( $('.variant-input-wrap').eq(1).length > 0){
var first_option = $('.variant-input-wrap').eq(0).find('.selected').attr('data-value');
var current_elem = $(this);
var unavailable = false;
$('.hidden-variant option').each(function(){
if($(this).attr('value') == first_option +' / ' + current_elem.attr('data-value') && $(this).attr('data-available') == 'true'){
current_elem.html(current_elem.attr('data-value') + '<span class="variant-label">In Stock</span>');
unavailable = true;
}
})
if(!unavailable){
current_elem.html($(this).attr('data-value') + '<span class="variant-label">Custom Made</span>'+ '<span class="variant-message">' + $('.hidden-variant option').attr('data-text') + '</span>');
}
}
else{
var current_elem = $(this);
var option_value = $(this).attr('data-value');
var unavailable = false;
$('.hidden-variant option').each(function(){
if($(this).attr('value') == option_value && $(this).attr('data-available') == 'true'){
current_elem.html(option_value+ '<span class="variant-label">In Stock</span>');
unavailable = true;
}
})
if(!unavailable){
current_elem.html($(this).attr('data-value')+ '<span class="variant-label">Custom Made</span>'+ '<span class="variant-message">'+$('.hidden-variant option').attr('data-text')+'</span>');
}
}
})
// update default
if($.trim($('.prettydropdown li.selected .variant-message').html())=='') {
$('.stock-message').html("In Stock");
} else if($.trim($('.prettydropdown li.selected .variant-message').html())!='') {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>" + "<span class='variant-message'>" + $('.prettydropdown li.selected .variant-message').html() + "</span>");
}
},500)
}
/**
* Public Functions
*/
// Resync the menu with <select> to reflect state changes
this.refresh = function(oOptions) {
return this.each(function() {
var $select = $(this);
$select.prevAll('ul').remove();
$select.unwrap().data('loaded', false);
this.size = $select.data('size');
init(this);
});
};
return this.each(function() {
init(this);
});
};
}(jQuery));
There was an issue with some products that have a blank variant message but are still "Custom Made". I updated the code to the following to try and fix that, but I don't see how it would pull in the correct value when there is no variant dropdown. Wouldn't it need to pull the info from the '.hidden-variant'? This product has no variants. This product has multiple
// update default
if($.trim($('.prettydropdown li.selected .variant-label').html())=='In Stock') {
$('.stock-message').html("In Stock");
} else if($.trim($('.prettydropdown li.selected .variant-label').html())=='Custom Made' && ($.trim($('.prettydropdown li.selected .variant-message').html())!='')) {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>" + "<span class='variant-message'>" + $('.prettydropdown li.selected .variant-message').html() + "</span>");
} else if($.trim($('.prettydropdown li.selected .variant-label').html())=='Custom Made' && ($.trim($('.prettydropdown li.selected .variant-message').html())=='')) {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>");
}
},500)
Hi @michaelmorgan,
Products without variants, will be updated here:
But the products with no variants don't have a '.prettydropdown li.selected .variant-label' since they don't have a dropdown. Wouldn't they need to pull the info from the '.hidden-variant' printed data? Like this product doesn't have a message displaying now.
Hi @michaelmorgan,
Means you want to hide it, you just need to remove the following code, and it will work fine.
I am not sure what you are saying. I want to display the message on all products. I updated the code to the following. It now displays the message for products with no variants but now the issue is for the products that have variants, when you change the variant, it reverts the message to the value of the first option after the 500ms. So it looks like the '.hidden-variant option' (used for the products without variants) is overriding. I think the code for the products with variants and ones without should be separate but I am unsure how to go about that.
// update default
if($.trim($('.prettydropdown li.selected .variant-label').html())=='In Stock' || $('.hidden-variant option').attr('data-available')=='true') {
$('.stock-message').html("<span class='variant-label'> In Stock </span>");
} else if($.trim($('.prettydropdown li.selected .variant-label').html())=='Custom Made' && ($.trim($('.prettydropdown li.selected .variant-message').html())!='')) {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>" + "<span class='variant-message'>" + $('.prettydropdown li.selected .variant-message').html() + "</span>");
} else if($.trim($('.prettydropdown li.selected .variant-label').html())=='Custom Made' && ($.trim($('.prettydropdown li.selected .variant-message').html())=='')) {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>");
} else if($('.hidden-variant option').attr('data-available')=='false' && $('.hidden-variant option').attr('data-text')=='') {
$('.stock-message').html("<span class='variant-label'> Custom Made </span>");
} else if($('.hidden-variant option').attr('data-available')=='false' && $('.hidden-variant option').attr('data-text')!='') {
$('.stock-message').html("<span class='variant-label'> Custom Made </span>" + "<span class='variant-message'>" + $('.hidden-variant option').attr('data-text') + "</span>");
}
},500)
.
Hey! I was messing around some more and added "$('.prettydropdown').length === 0" to the ".hidden-variant" parts and it worked like a charm. Its good to go now!
// update default
if($.trim($('.prettydropdown li.selected .variant-label').html())=='In Stock' || $('.hidden-variant option').attr('data-available')=='true' && $('.prettydropdown').length === 0) {
$('.stock-message').html("<span class='variant-label'> In Stock </span>");
} else if($.trim($('.prettydropdown li.selected .variant-label').html())=='Custom Made' && ($.trim($('.prettydropdown li.selected .variant-message').html())!='')) {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>" + "<span class='variant-message'>" + $('.prettydropdown li.selected .variant-message').html() + "</span>");
} else if($.trim($('.prettydropdown li.selected .variant-label').html())=='Custom Made' && ($.trim($('.prettydropdown li.selected .variant-message').html())=='')) {
$('.stock-message').html("<span class='variant-label'>" + $('.prettydropdown li.selected .variant-label').html() + "</span>");
} else if($('.hidden-variant option').attr('data-available')=='false' && $('.hidden-variant option').attr('data-text')=='' && $('.prettydropdown').length === 0) {
$('.stock-message').html("<span class='variant-label'> Custom Made </span>");
} else if($('.hidden-variant option').attr('data-available')=='false' && $('.hidden-variant option').attr('data-text')!='' && $('.prettydropdown').length === 0) {
$('.stock-message').html("<span class='variant-label'> Custom Made </span>" + "<span class='variant-message'>" + $('.hidden-variant option').attr('data-text') + "</span>");
}
},500)
Hi @michaelmorgan,
If it helped you solve your issue, please mark it as a solution. Thank you and good luck.
Hello Sir/Madam,
I would like to know about Shopify operate in Cambodia.
How it work ?
Learn how to expand your operations internationally with Shopify Academy’s learning path...
By Shopify Feb 4, 2025Hey Community, happy February! Looking back to January, we kicked off the year with 8....
By JasonH Feb 3, 2025Expand into selling wholesale with Shopify Academy’s learning path, B2B on Shopify: Lau...
By Shopify Jan 28, 2025