Welcome to WebmasterWorld Guest from 54.167.46.29

Forum Moderators: open

Message Too Old, No Replies

toggle through images on click

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

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


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 July 26, 2013 (gmt 0)

Senior Member from US 

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

joined:Oct 17, 2005
posts: 4965
votes: 10


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 July 26, 2013 (gmt 0)

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


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

Senior Member from US 

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

joined:Oct 17, 2005
posts: 4965
votes: 10


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 July 26, 2013 (gmt 0)

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


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 July 26, 2013 (gmt 0)

Senior Member from US 

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

joined:Oct 17, 2005
posts: 4965
votes: 10


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 July 26, 2013 (gmt 0)

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


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 July 26, 2013 (gmt 0)

Senior Member from US 

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

joined:Oct 17, 2005
posts: 4965
votes: 10


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 July 26, 2013 (gmt 0)

Senior Member from US 

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

joined:Oct 17, 2005
posts: 4965
votes: 10


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

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


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 July 26, 2013 (gmt 0)

Senior Member from US 

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

joined:Oct 17, 2005
posts: 4965
votes: 10


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 July 26, 2013 (gmt 0)

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


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 July 26, 2013 (gmt 0)

Senior Member from US 

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

joined:Oct 17, 2005
posts: 4965
votes: 10


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 July 26, 2013 (gmt 0)

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


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 July 27, 2013 (gmt 0)

Senior Member from US 

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

joined:Oct 17, 2005
posts: 4965
votes: 10


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 July 27, 2013 (gmt 0)

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


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

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


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)

Senior Member from US 

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

joined:Oct 17, 2005
posts: 4965
votes: 10


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)

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


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)

Senior Member from US 

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

joined:Oct 17, 2005
posts: 4965
votes: 10


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)

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


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)

Senior Member from US 

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

joined:Oct 17, 2005
posts: 4965
votes: 10


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)

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


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)

Senior Member from US 

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

joined:Oct 17, 2005
posts: 4965
votes: 10


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)

Junior Member

5+ Year Member

joined:July 17, 2006
posts:137
votes: 0


Many thanks for your help Fotiman, much appreciated.