Can anyone see anything that is wrong with this code it just isn't working...
I am tring to:
get the value of #product-variants-option-0
search #preload for the relevant image and
then change div.image img src to that image
jQuery(document).ready(function($) {
$('#product-variants-option-0').change(function() {
// What is the sku of the current variant selection.
var select_value = $(this).find(':selected').val();
if (select_value == "Kelly Green") {
var keyword = "kly";
};
var new_src = $('#preload img[src*=keyword]');
$('div.image img').attr('src', new_src);
});
});
The selection:
<select class="single-option-selector-0" id="product-variants-option-0">
<option value="Kelly Green">Kelly Green</option>
<option value="Navy">Navy</option>
<option value="Olive">Olive</option>
<option value="Cocoa">Cocoa</option>
</select>
I'm trying to search an unordered list:
<ul id="preload" style="display:none;">
<li><img src="0z-kelly-green-medium.jpg"/></li>
<li><img src="0z-olive-medium.jpg"/></li>
</ul>
The image I'm trying to replace is this:
I see a few problems:
- You're not converting "Kelly Green" to "kelly".
- The
var new_src = $('#preload img[src*=keyword]');
has keyword
hardcoded into it (not the value of the keyword variable).
The li
s in the list don't have img
elements inside them (they just directly contain the URL as text). You've edited the question and fixed that.
- If the select value isn't "Kelly Green" you're not making it lower case, and you're not using the value at all.
- You're not retrieving the
src
attribute of the preload image.
If you change the list to:
<ul id="preload" style="display:none;">
<li><img src='0z-kelly-green-medium.jpg'></li>
<li><img src='0z-olive-medium.jpg'></li>
</ul>
(That was part of what was fixed.)
Then this should work:
jQuery(document).ready(function($) {
$('#product-variants-option-0').change(function() {
var select_value, keyword, new_src;
// What is the sku of the current variant selection
select_value = $(this).find(':selected').val();
// Get the keyword to use (the value in lower case, or "kelly" if the
// value is "Kelly Green")
keyword = select_value == "Kelly Green" ? "kelly" : select_value.toLowerCase();
// Find the image using that `src`, note that we concatenate the value
// from `keyword`, rather than having it in a literal.
new_src = $('#preload img[src*=' + keyword + ']').attr('src');
// Set the image's source.
$('div.image img').attr('src', new_src);
});
});
Live example
Charles, you asked for input on how it might be written differently, and I said I had a minute to do something up. Sorry for the delay, my Real Job needed me for a moment.
I'd probably approach it like this, with the assumption that you have this kind of select box elsewhere in your application and therefore generalization is worthwhile.
- Make things reusable wherever possible (well, almost; there's one bit of generalization I left as an exercise to the reader).
- Don't store the image URLs in one place and the options in another; put them together, so they can both come from the same data source easily. This reduces error. (For instance, in your question, you have four options, but you only have images for two of them in the preload structure. Now, if you don't have images for the others, that's fine, leave the attribute off or make it blank, but keeping things together / generated from the same source is a good idea.)
- Do #2 with the
data-image
attribute, which is valid as of HTML5 and perfectly harmless in earlier versions. (Details)
- Don't include the markup for the preloading in the HTML; generate it. This relates to #2, and also to the fact that users who don't have JavaScript don't need the precached images as they won't be used. So don't push them things they don't need.
HTML:
<select class="single-option-selector-0" id="product-variants-option-0">
<option
value="Kelly Green"
data-image="0z-kelly-green-medium.jpg"
>Kelly Green</option>
<option
value="Navy"
data-image="0z-navy-medium.jpg"
>Navy</option>
<option
value="Olive"
data-image="0z-olive-medium.jpg"
>Olive</option>
<option
value="Cocoa"
data-image="0z-cocoa-medium.jpg"
>Cocoa</option>
</select>
and
<div class='image'><img src='placeholder.jpg'></div>
JavaScript with jQuery:
(function($) {
// A utility function from my arsenal; you can
// just inline this if you don't want it.
// Returns an array containing the given attribute
// from *all* of the elements in the jQuery object.
// Args:
// name Name of the attribute to fetch
// blanksOkay (Optional, default false) true if
// you want blanks in the array for
// blank entries or non-existant entries;
// false if you want them left out.
$.fn.attrAll = function(name, blanksOkay) {
var list, index;
if (typeof blanksOkay === "undefined") {
blanksOkay = false;
}
list = [];
for (index = 0; index < this.length; ++index) {
entry = $(this[index]).attr(name);
if (entry || blanksOkay) {
list.push(entry);
}
}
return list;
};
})(jQuery);
// The page's ready script
jQuery(function($) {
// Set up the product variants select box.
// You could generalize this with classes or other attributes
// (so there would be *nothing* special about the select box),
// but I didn't want to change your markup too much.
setupSelectWithImages(
'#product-variants-option-0',
'div.image img:first'
);
// ===
// All of the following would probably be in your
// utility script; it's not page-specific.
// ===
// Set up our select box that's equipped with images
// so it shows the image when an option is selected.
// The options within the box should have data-image
// attributes for their images, which are precached.
// Args:
// boxSelector The selector that finds the select box
// targetSelector The selector that finds the target img
function setupSelectWithImages(boxSelector, targetSelector) {
var box;
// Get the select box
box = $(boxSelector);
// Preload the images
preloadImages(box.find('option'), 'data-image');
// Ensure we show the correct image when the select box
// changes, and force showing it right now for the default
// value.
setCurrentImage.call(box[0]);
box.change(setCurrentImage);
function setCurrentImage() {
var entry = $(this).find('option:selected').attr('data-image');
if (entry) {
display("Setting src to " + entry);
$(targetSelector).attr('src', entry);
}
}
// Done with box
box = undefined;
}
// Another general purpose function; preloads the images
// defined by the given attribute on the elements in the
// given jQuery object.
// I've kept things bundled up (in a div rather than a ul),
// but there's no special reason to, you could just add
// the individual images to the body directly.
// Using a container makes it easy to return a single
// thing out of this function, which may be useful
// to some calling code.
function preloadImages(list, attrName) {
var markup;
// Get a list of the relevant attribute
markup = list.attrAll('data-image');
// Convert it into a bunch of img tags
markup = joinEntries(markup, "<img src='", "'>");
// Put them in an off-page div, add it to the document,
// and return the div to the caller
return $("<div/>").css({
'position': 'absolute',
'left': '-10000px',
'top': '0px'
}).html(markup).appendTo(document.body);
}
// Join the entries in the array with the given
// prefix and suffix.
function joinEntries(a, prefix, suffix) {
prefix = prefix || '';
suffix = suffix || '';
return prefix + a.join(suffix + prefix) + suffix;
}
// This is just for our purposes in this demo
function display(msg) {
$("<p/>").html(msg).appendTo(document.body);
}
});
Live example (but the live example uses some gravatars, so you can actually see the images)
$('#preload img[src*=keyword]');
will not find anything, there is no img
inside #preload
. You should define id
for every li
, and these ids will equal you keywords. After that you can do $('#preload #' + keyword).text()
- this will return correct new_src
value
UPDATE
After your edit: do not put images inside li
s! This will needlessly increase traffic! Put just sources:
<li id="kly">pathto.jpg</li>