Welcome to WebmasterWorld Guest from 54.167.177.207

Forum Moderators: open

toggle through images on click

   
12:09 pm on Jul 26, 2013 (gmt 0)

5+ Year Member



wondering if anyone can help me. i am looking for a javascript that toggles through a set of 3 images 1.jpg, 2.jpg and 3.jpg. when my page loads, i need to be able to tell it which of the 3 images it starts with so e.g. if i start on 2.jpg, then 1 click will go to 3.jpg, 2 click will go to 1.jpg etc. Also, when these images are toggled, i need the value of a hidden form field called details to change to match the filename. can anyone help?

thanks
1:03 pm on Jul 26, 2013 (gmt 0)

WebmasterWorld Senior Member fotiman is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



What should the behavior be if JavaScript is disabled? Do you show only 1 of the 3 images, or do you show them all?
1:15 pm on Jul 26, 2013 (gmt 0)

5+ Year Member



If javascript is disabled then show no image or a different image e.g. error.jpg
2:34 pm on Jul 26, 2013 (gmt 0)

WebmasterWorld Senior Member fotiman is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



Ok, it's not really good UX to do that though. You might also be alienating some disabled users, so you might rethink that decision. JavaScript is best used for "Progressive Enhancement" as opposed to a requirement.

In any case:
HTML:

<img src="error.jpg" id="foo" data-images="1.jpg,2.jpg,3.jpg" data-image-index="1" />


JavaScript:

(function () {
var foo = document.getElementById('foo'),
images = foo.getAttribute('data-images'),
image-index = foo.getAttribute('data-image-index'),
n;

if (images) {
images = images.split(",");
image-index = (image-index? parseInt(image-index, 10): 0);
n = images.length;

function nextImage() {
image-index = (image-index + 1 < n? image-index + 1: 0);
foo.src = images[image-index];
}
nextImage();
foo.onclick = nextImage;
}
})();


Add any images that you want to swap to the data-images attribute as a comma separated list (note, the script code doesn't trim off any whitespace, though it wouldn't be difficult to add... in the mean time, make sure no spaces between items). You can (optionally) specify which item to start on with the data-image-index attribute (zero based, so if you have 3 items in the list the value can be 0, 2, or 2).

I didn't test this code, so let me know if it doesn't work. :)
3:25 pm on Jul 26, 2013 (gmt 0)

5+ Year Member



Thanks, but doesnt seem to be toggling, i tried adding the javascript either before or after the html but no luck. do i need to call the function in the image tag as an onclick?
3:40 pm on Jul 26, 2013 (gmt 0)

WebmasterWorld Senior Member fotiman is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



My bad. I had replaced a variable name with "image-index" (the "-" is not valid as a variable name). Try this:



(function () {
var foo = document.getElementById('foo'),
images = foo.getAttribute('data-images'),
imageindex = foo.getAttribute('data-image-index'),
n;

if (images) {
images = images.split(",");
imageindex = (imageindex? parseInt(imageindex, 10): 0);
n = images.length;


function nextImage() {
imageindex = (imageindex + 1 < n? imageindex + 1: 0);
foo.src = images[imageindex];
}
nextImage();
foo.onclick = nextImage;
}
})();
3:53 pm on Jul 26, 2013 (gmt 0)

5+ Year Member



awesome that works :)

there are 2 issues, firstly the data-image-index 0 is giving me 2.jpg, 1 is giving me 3.jpg and 2 is giving me 1.jpg, just wondering why its not in the same sequence as it is defined in data-images?

also if i put this image inside a form and submit the form as a GET action, i dont seem to get any value from the image data.

Many thanks for your help.
4:28 pm on Jul 26, 2013 (gmt 0)

WebmasterWorld Senior Member fotiman is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



1. That's a bug, but easily fixed.
2. I forgot about your requirement to update a hidden field. That's easy too.

Try this instead:

(function () {
var foo = document.getElementById('foo'),
details = document.getElementById('details'),
images = foo.getAttribute('data-images'),
imageindex = foo.getAttribute('data-image-index'),
n;

if (images) {
images = images.split(",");
imageindex = (imageindex? parseInt(imageindex, 10): 0);
n = images.length;

function setImg(el, src) {
el.src = src;
details.value = src;
}

function nextImage() {
imageindex = (imageindex + 1 < n? imageindex + 1: 0);
setImg(foo, images[imageindex]);
}

setImg(foo, images[imageindex]);
foo.onclick = nextImage;

}
})();
4:29 pm on Jul 26, 2013 (gmt 0)

WebmasterWorld Senior Member fotiman is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



Note, that example assumes you have a hidden element with an id of "details" on the page.
4:58 pm on Jul 26, 2013 (gmt 0)

5+ Year Member



Awesome, works very well. Many thanks. If on one page, i wanted multiple instances of this, for example first instance would be foo and details, second would be foo2 and details2, i can simply just replicate this code and just change those. But just wondering if there is anyway to reduce the amount of code to replicate? e.g keep the repetitive functions in one code and repeat the code for each instance? (if that makes sense)

Many thanks once again for your help.
9:03 pm on Jul 26, 2013 (gmt 0)

WebmasterWorld Senior Member fotiman is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



Here's a very quick attempt to abstract it out into something more reusable. This could probably be vastly improved, but the following works:


(function () {
function ImageToggler(id, hiddenInputId) {
this.img = document.getElementById(id);
this.details = document.getElementById(hiddenInputId);
this.images = this.img.getAttribute('data-images');
this.imageindex = this.img.getAttribute('data-image-index');

this._init();
}

ImageToggler.prototype._init = function () {
var that = this;
if (this.images) {
this.images = this.images.split(",");
this.imageindex = (this.imageindex? parseInt(this.imageindex, 10): 0);
this.n = this.images.length;
this._setImg(this.img, this.images[this.imageindex]);
this.img.onclick = function () {that._nextImage.call(that);};
}
}


ImageToggler.prototype._setImg = function(el, src) {
el.src = src;
this.details.value = src;
console.log(src);
}

ImageToggler.prototype._nextImage = function () {
this.imageindex = (this.imageindex + 1 < this.n? this.imageindex + 1: 0);
this._setImg(this.img, this.images[this.imageindex]);
}


var foo = new ImageToggler('foo','details');
var foo2 = new ImageToggler('foo2', 'details2');

})();

And the corresponding markup:

<img src="error.jpg" id="foo" data-images="1.jpg,2.jpg,3.jpg" data-image-index="1" />
<input type="hidden" id="details" name="details" />
<img src="error.jpg" id="foo2" data-images="4.jpg,5.jpg,6.jpg" data-image-index="2" />
<input type="hidden" id="details2" name="details2" />
11:02 pm on Jul 26, 2013 (gmt 0)

5+ Year Member



Many thanks, it works really well. I'm guessing i will have to place all the markup html tags first, and then once finished with all of them add the script at the end.

One last question, if i wanted this.details.value to be imageindex instead of src, how can this be achieved with this new code, with the old one i changed it to details.value = imageindex;

Many thanks once again, much appreciated.
11:08 pm on Jul 26, 2013 (gmt 0)

WebmasterWorld Senior Member fotiman is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



Just change the calls to _setImage (there are 2 of them) from this:
this._setImg(this.img, this.images[this.imageindex]);
to
this._setImg(this.img, this.imageindex);
11:28 pm on Jul 26, 2013 (gmt 0)

5+ Year Member



sorry, i meant to change the actual value of hidden field from the image src to the actual imageindex, i think changing the 2 you suggested changes the actual image.

Thanks
12:11 am on Jul 27, 2013 (gmt 0)

WebmasterWorld Senior Member fotiman is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



Oh, you're right. :) So after making that change, then modify the _setImg function to this:

ImageToggler.prototype._setImg = function(el, idx) {
el.src = this.images[idx];
this.details.value = idx;
}
12:19 am on Jul 27, 2013 (gmt 0)

5+ Year Member



Perfect :) Many thanks. Much appreciated.
1:46 am on Jul 30, 2013 (gmt 0)

5+ Year Member



Just a quick question, if i have a hyperlink that i want to directly link with either javascript: or onclick to directly change and toggle lets say foo2 and details2, is there any way this can be done?

So for example, if i have the following markup:


<img src="error.jpg" id="foo" data-images="1.jpg,2.jpg,3.jpg" data-image-index="1" />
<input type="hidden" id="details" name="details" />
<img src="error.jpg" id="foo2" data-images="4.jpg,5.jpg,6.jpg" data-image-index="2" />
<input type="hidden" id="details2" name="details2" />


i would like a text that onclick i can change foo2 and details2 to a certain index.

Thanks
1:28 am on Aug 1, 2013 (gmt 0)

WebmasterWorld Senior Member fotiman is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



Assuming you have a link like this:
<a href="2.jpg" id="foo_2jpg">2.jpg</a>

Then your script code could do this (after you define foo as an ImageToggler):

document.getElementById('foo_2jpg').onclick = function() {
foo._setImg(foo.img, 2);
};
2:40 am on Aug 1, 2013 (gmt 0)

5+ Year Member



Is there not a way to do it maybe something like this:
<div onclick="foo._setImg(s1.img, 2);">2.jpg</div>
3:23 am on Aug 1, 2013 (gmt 0)

WebmasterWorld Senior Member fotiman is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



I generally advise against using inline scripting (unobtrusive JavaScript makes it easier to maintain). Also, I forgot to add return false; to the end of the function to prevent the default action. Lastly, setImg probably doesn't need to take the img element since ImageToggler has access to the this.img property (which is what's being passed in each call to setImg).
10:51 am on Aug 1, 2013 (gmt 0)

5+ Year Member



Thanks Fotiman,

But is there a way to make the inline scripting work in this instance? because the example i gave above doesnt seem to work.

Also, i tried your example with the href, but doesnt seem to work.


I have the imageToggler defined as:

var foo = new ImageToggler('foo','details');


and then below that i added:

document.getElementById('foo_2jpg').onclick = function() {
foo._setImg(foo.img, 2);
return false;
};


and then for the markup i added:

<a href="2.jpg" id="foo_2jpg">2.jpg</a> 


But doesnt seem to be working.
9:56 pm on Aug 1, 2013 (gmt 0)

WebmasterWorld Senior Member fotiman is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



Ok, first, since we're going to treat setImg as more of a public method, we should rename it to not start with an underscore (it's just a common convention that you name methods that are not meant to be called publicly with a leading underscore).
Next, lets change it so we don't need to pass in an element.
So:


ImageToggler.prototype.setImg = function(idx) {
this.img.src = this.images[idx];
this.details.value = idx;
}

Then change the two lines that called _setImg to not pass an element.

this.setImg(this.images[this.imageindex]);

Then with your link:

<a href="2.jpg" id="foo_2jpg">2.jpg</a>

And your script code should be:

document.getElementById('foo_2jpg').onclick = function() {
foo.setImg.call(foo, 2);
return false;
};
11:18 pm on Aug 1, 2013 (gmt 0)

5+ Year Member



Sorry but doesnt seem to be working, as soon as I add the new ImageToggler code and replace the two lines that called _setImg, the images stopped showing altogether. Here is how the code currently looks:



<a href="2.jpg" id="foo_2jpg">2.jpg</a>


<script type="text/javascript">
<!--

(function () {
function ImageToggler(id, hiddenInputId) {
this.img = document.getElementById(id);
this.details = document.getElementById(hiddenInputId);
this.images = this.img.getAttribute('data-images');
this.imageindex = this.img.getAttribute('data-image-index');

this._init();
}

ImageToggler.prototype._init = function () {
var that = this;
if (this.images) {
this.images = this.images.split(",");
this.imageindex = (this.imageindex? parseInt(this.imageindex, 10): 0);
this.n = this.images.length;
this.setImg(this.images[this.imageindex]);
this.img.onclick = function () {that._nextImage.call(that);};
}
}


ImageToggler.prototype.setImg = function(idx) {
this.img.src = this.images[idx];
this.details.value = idx;
}


ImageToggler.prototype._nextImage = function () {
this.imageindex = (this.imageindex + 1 < this.n? this.imageindex + 1: 0);
this.setImg(this.images[this.imageindex]);
}



var foo = new ImageToggler('foo','details');
var foo2 = new ImageToggler('foo2','details2');



})();

document.getElementById('foo_2jpg').onclick = function() {
foo.setImg.call(foo, 2);
return false;
};

</script>
12:05 am on Aug 2, 2013 (gmt 0)

WebmasterWorld Senior Member fotiman is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



First, don't include HTML comments within your script tags. That's an old practice that hasn't been needed for over a decade.

Here's an updated version that should work:

(function () {
function ImageToggler(id, hiddenInputId) {
this.img = document.getElementById(id);
this.details = document.getElementById(hiddenInputId);
this.images = this.img.getAttribute('data-images');
this.imageindex = this.img.getAttribute('data-image-index');

this._init();
}

ImageToggler.prototype._init = function () {
var that = this;
if (this.images) {
this.images = this.images.split(",");
this.imageindex = (this.imageindex? parseInt(this.imageindex, 10): 0);
this.n = this.images.length;
this.setImg(this.imageindex);
this.img.onclick = function () {that._nextImage.call(that);};
}
}


ImageToggler.prototype.setImg = function(idx) {
this.imageindex = idx;
this.img.src = this.images[idx];
this.details.value = idx;
console.log(this.img.src);
}


ImageToggler.prototype._nextImage = function () {
this.imageindex = (this.imageindex + 1 < this.n? this.imageindex + 1: 0);
this.setImg(this.imageindex);
}

var foo = new ImageToggler('foo','details');
var foo2 = new ImageToggler('foo2','details2');

document.getElementById('foo_2jpg').onclick = function() {
foo.setImg.call(foo, 2);
return false;
};

})();
2:02 am on Aug 2, 2013 (gmt 0)

5+ Year Member



Many thanks for your help Fotiman, much appreciated.
 

Featured Threads

Hot Threads This Week

Hot Threads This Month