homepage Welcome to WebmasterWorld Guest from 54.227.67.210
register, free tools, login, search, subscribe, help, library, announcements, recent posts, open posts,
Subscribe to WebmasterWorld
Home / Forums Index / Code, Content, and Presentation / JavaScript and AJAX
Forum Library, Charter, Moderator: open

JavaScript and AJAX Forum

    
toggle through images on click
ahmed24




msg:4596712
 12:09 pm on Jul 26, 2013 (gmt 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

 

Fotiman




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

What should the behavior be if JavaScript is disabled? Do you show only 1 of the 3 images, or do you show them all?

ahmed24




msg:4596728
 1:15 pm on Jul 26, 2013 (gmt 0)

If javascript is disabled then show no image or a different image e.g. error.jpg

Fotiman




msg:4596746
 2:34 pm on Jul 26, 2013 (gmt 0)

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. :)

ahmed24




msg:4596763
 3:25 pm on Jul 26, 2013 (gmt 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?

Fotiman




msg:4596766
 3:40 pm on Jul 26, 2013 (gmt 0)

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;
}
})();

ahmed24




msg:4596768
 3:53 pm on Jul 26, 2013 (gmt 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.

Fotiman




msg:4596779
 4:28 pm on Jul 26, 2013 (gmt 0)

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;

}
})();

Fotiman




msg:4596780
 4:29 pm on Jul 26, 2013 (gmt 0)

Note, that example assumes you have a hidden element with an id of "details" on the page.

ahmed24




msg:4596794
 4:58 pm on Jul 26, 2013 (gmt 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.

Fotiman




msg:4596850
 9:03 pm on Jul 26, 2013 (gmt 0)

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" />

ahmed24




msg:4596876
 11:02 pm on Jul 26, 2013 (gmt 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.

Fotiman




msg:4596880
 11:08 pm on Jul 26, 2013 (gmt 0)

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);

ahmed24




msg:4596884
 11:28 pm on Jul 26, 2013 (gmt 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

Fotiman




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

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;
}

ahmed24




msg:4596890
 12:19 am on Jul 27, 2013 (gmt 0)

Perfect :) Many thanks. Much appreciated.

ahmed24




msg:4597562
 1:46 am on Jul 30, 2013 (gmt 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

Fotiman




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

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);
};

ahmed24




msg:4598293
 2:40 am on Aug 1, 2013 (gmt 0)

Is there not a way to do it maybe something like this:
<div onclick="foo._setImg(s1.img, 2);">2.jpg</div>

Fotiman




msg:4598305
 3:23 am on Aug 1, 2013 (gmt 0)

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).

ahmed24




msg:4598370
 10:51 am on Aug 1, 2013 (gmt 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.

Fotiman




msg:4598534
 9:56 pm on Aug 1, 2013 (gmt 0)

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;
};

ahmed24




msg:4598574
 11:18 pm on Aug 1, 2013 (gmt 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>

Fotiman




msg:4598595
 12:05 am on Aug 2, 2013 (gmt 0)

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;
};

})();

ahmed24




msg:4598632
 2:02 am on Aug 2, 2013 (gmt 0)

Many thanks for your help Fotiman, much appreciated.

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / JavaScript and AJAX
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved