PDA

View Full Version : [SOLVED] javascript onclick array matters



maclenin
January 19th, 2012, 12:53 PM
I am having difficulty "wrangling" output from the following....

I am creating a script which, essentially, pushes elements from a single multi-dimensional reference array, into a handful of smaller sub-arrays, to yield a series of web-based thumbnail galleries (A,B and C).

Each of the images within the thumbnail galleries has an onclick event handler to bring up a larger version of the image, ideally, on click.... However, I am having trouble configuring the onclick function, properly.

A. BACKGROUND

1. The reference array is made up of 10 elements, each of which is "tagged" ("A","B","C") to "associate" it with a unique sub-array or gallery:


var ref=new Array();

ref[0]=new Array ("image0","A");
ref[1]=new Array ("image1","A");
ref[2]=new Array ("image2","B");
ref[3]=new Array ("image3","A");
ref[4]=new Array ("image4","B");
ref[5]=new Array ("image5","C");
ref[6]=new Array ("image6","C");
ref[7]=new Array ("image7","C");
ref[8]=new Array ("image8","A");
ref[9]=new Array ("image9","A");

var rlen=ref.length;

2. Each of the sub-arrays is generated on web page load...


<body onload="create_sub_A(); create_sub_B(); create_sub_C();">

3. ...via these functions:



var=sub;

function create_sub_A() {sub="A"; create_new_array(); set_up_gallery();}
function create_sub_B() {sub="B"; create_new_array(); set_up_gallery();}
function create_sub_C() {sub="C"; create_new_array(); set_up_gallery();}

4. which each call:


function create_new_array()
{
sub_Array=new Array();
for (i=0; i<=rlen; i++)
{
x=ref[i][1];
if (sub==x)
{
sub_Array.push(i);
}
slen=sub_Array.length;
}

5. and the gallery set up function, which displays the thumbnail galleries in sub-array-defined groups:


function set_up_gallery()
{
for (i=0; i<=slen; i++)
{
id=i;
document.getElementById(sub+"_thumbnail<img>"+id).src=ref[sub_Array[i]][0];
document.getElementById(sub+"_thumbnail<a>"+id).onclick=larger_image(sub_Array[i]);
console.log(sub+sub_Array[i]);
}

thumbnail gallery A - comprises 4 images (image0,image1,image8,image9)
thumbnail gallery B - comprises 2 images (image2,image4)
thumbnail gallery C - comprises 4 images (image3,image5,image6,image7)

6. Finally, here is the "larger_image" function, which I have yet to get working properly. The problem occurs when I try to define the call to the onclick function as I show in step 5.


function larger_image(a)
{
current_image=a; document.getElementById("lg_image").src=ref[sub_Array[current_image]][0];
}

B. THE CRUX?

a is the value of sub_Array (or is it the "i" within that statement?) for each respective thumbnail - which corresponds to the original ref array index values.

For example, if I wanted to see a larger image0 - I [I]should be able to click on the first image in thumbnail gallery A, which should pass 0 from the thumbnail via onclick="larger_image(sub_Array[i])" - completing src=ref[0][0]; to bring up image0....

However, I can't get onclick defined in such a way as to allow me bring up the larger image (note: thumbnails are currently defined by height="50" in the html).

After I assign the onclick value (see step 5.) and refresh the web page, the large images cycle from first to last, automatically, as if the onclick "button" were being held down as the web page loaded....

console.log(sub+sub_Array[i]);, as defined in step 5. shows that the proper values are being generated by... sub_Array[i] ? ...

A0
A1
B2
A3
B4
C5
C6
C7
A8
A9

...they (the numbers, that is) just aren't being assigned to the onclick event handler properly....

Thanks for any wisdom.

Dimarchi
January 23rd, 2012, 05:23 PM
Can you provide a link to a test page, or a zipped file with the necessary files? I have a similar thing on my own pages, working a bit differently, though. There's an element with an id reserved for larger picture to which I place the random clicked (scaled) picture in its full size. If you like, I can post the code for it.

maclenin
January 23rd, 2012, 10:36 PM
Dimarchi!

Thanks for the reply! Let me see if I can clarify, more explicitly - with some simple html (slightly abridged from the JS examples).

html

<!--thumbnail_gallery_A-->
<a id="A_tn<a>0" onclick="lrgr_image(0)"><img id="A_tn<img>0" src="image0" height="50"></a>
<a id="A_tn<a>1" onclick="lrgr_image(1)"><img id="A_tn<img>1" src="image1" height="50"></a>
<a id="A_tn<a>2" onclick="lrgr_image(3)"><img id="A_tn<img>2" src="image3" height="50"></a>
<a id="A_tn<a>3" onclick="lrgr_image(8)"><img id="A_tn<img>3" src="image8" height="50"></a>
<a id="A_tn<a>4" onclick="lrgr_image(9)"><img id="A_tn<img>4" src="image9" height="50"></a>

<!--thumbnail_gallery_B-->
<a id="B_tn<a>0" onclick="lrgr_image(2)"><img id="B_tn<img>0" src="image2" height="50"></a>
<a id="B_tn<a>1" onclick="lrgr_image(4)"><img id="B_tn<img>1" src="image4" height="50"></a>

<!--thumbnail_gallery_C-->
<a id="C_tn<a>0" onclick="lrgr_image(5)"><img id="C_tn<img>0" src="image5" height="50"></a>
<a id="C_tn<a>1" onclick="lrgr_image(6)"><img id="C_tn<img>1" src="image6" height="50"></a>
<a id="C_tn<a>2" onclick="lrgr_image(7)"><img id="C_tn<img>2" src="image7" height="50"></a>

<!--larger_image-->
<div id="lg_image_div"><img id="lg_image" src=""></div>

[THIS IS WORKING AS IT SHOULD IN MY MODEL] The black numbers are the values of "id" in step 5. These tell us HOW MANY images have been assigned to each thumbnail gallery, and play a part in describing the order in which the images will appear in each thumbnail gallery.

[THIS IS WORKING AS IT SHOULD IN MY MODEL] The green numbers are the respective values of "i" in sub_Array.push(i) from step. 4., which, when incorporated in this manner: ref[[i][0], in step 5., reference WHICH images have been assigned to each thumbnail gallery.

[THIS IS THE ISSUE IN MY MODEL] The orange numbers are also the respective values of "i" in sub_Array.push(i) from step. 4., which, when incorporated as a, in this manner...


function lrgr_image(a)
{
current_image=a; document.getElementById("lg_image").src=ref[sub_Array[current_image]][0];
}

...in step 6., SHOULD tell us WHICH images have been assigned to <img id="lg_image" src=""> when a thumbnail is clicked.

I cannot get the orange numbers assigned to the onclick function properly.

Thanks, again, for any guidance!

simeon87
January 23rd, 2012, 10:55 PM
You're calling the larger_image function like this:


document.getElementById(sub+"_thumbnail<a>"+id).onclick=larger_image(sub_Array[i]);

But in larger_image you do this:


function lrgr_image(a)
{
current_image=a; document.getElementById("lg_image").src=ref[sub_Array[current_image]][0];
}

That's weird. You're passing an element on an array (sub_Array[i]) which is then used as index of that same array in larger_image. Shouldn't it be ref[a][0] ?

Furthermore, the reason you're having trouble is that your function are computing the same values (indices) in multiple places. All you need are:

- the reference array
- a function that gathers the images of gallery X from the reference array
- a function that outputs the HTML for gallery X

The following code can be improved:


<body onload="create_sub_A(); create_sub_B(); create_sub_C();">

function create_sub_A() {sub="A"; create_new_array(); set_up_gallery();}
function create_sub_B() {sub="B"; create_new_array(); set_up_gallery();}
function create_sub_C() {sub="C"; create_new_array(); set_up_gallery();}

I think it should look more like this:


<body onload="create_gallery("A"); create_gallery("B"); create_gallery("C");">

function create_gallery(identifier) {
// create array
// set up gallery
}

maclenin
January 24th, 2012, 12:44 AM
simeon87!

Yes - allow me to simplify (and clarify)....

1. reference array


var ref=new Array();
ref[0]=new Array ("image0","A");
ref[1]=new Array ("image1","A");
ref[2]=new Array ("image2","B");
ref[3]=new Array ("image3","C");
ref[4]=new Array ("image4","B");
var rlen=ref.length;

2. <body> work


<body onload="create_gallery('A'); create_gallery('B'); create_gallery('C');">

3. a function that gathers images from reference array and creates output to html for gallery X


function create_gallery(alpha)
{
sub_Array=new Array();
for (i=0; i<=rlen; i++)
{
x=ref[i][1];
if (alpha==x)
{
sub_Array.push(i);
}
}
slen=sub_Array.length;
for (i=0; i<=slen; i++)
{
id=i;
document.getElementById(alpha+"tImage"+id).src=ref[sub_Array[i]][0];
document.getElementById(alpha+"_tLarge"+id).onclick=large_image(sub_Array[i]);
}
}
4. function that should (but still doesn't) answer the onclick call to bring up the large_image

function large_image(Lg)
{
current_image=Lg; document.getElementById("lg_image").src=ref[current_image][0];
}


I still can't get the large_image onclick function to behave.... As it's written, the onclick seems to fire on page load - bringing up all the images - automatically - in rapid succession.... Stuck on this one....

Thanks for the help.

maclenin
January 24th, 2012, 10:59 AM
Aside from the fact that I need to build a better mousetrap, I think the key is understanding why...

...this WORKS...
document.getElementById("").src=ref[sub_Array[i]][0];
...and this does NOT:
document.getElementById("").onclick=large_image(sub_Array[i]);

epicoder
January 24th, 2012, 05:40 PM
document.getElementById("").onclick=large_image(sub_Array[i]);This does not work because you are assigning the return value of large_image(sub_Array[i]) to onclick. Use this code instead to set onclick:


document.getElementById("").setAttribute("onclick", "large_image(sub_Array[i])");Note the quotes around large_image. Without them, the return value will be assigned instead of the function itself to onclick.

Dimarchi
January 24th, 2012, 06:26 PM
It seems you are trying to achieve pretty much what I have done, so...here is what I did. All this code resides in a Javascript file, linked on the web page with the script tag. Two functions take care of the whole thing.



// addEvent function from http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html
function addEvent(obj, type, fn)
{
if (obj.addEventListener)
{
obj.addEventListener(type, fn, false);
}
else if (obj.attachEvent)
{
obj["e"+type+fn] = fn;
obj[type+fn] = function()
{
obj["e"+type+fn](window.event);
}
obj.attachEvent("on"+type, obj[type+fn]);
}
}

function biggerPicture(e)
{
if (e.target.nodeName.toLowerCase() == 'img')
{
e.preventDefault();
var pic = e.target;
var removeCanvas = document.getElementById('biggerPicture');
while (removeCanvas.childNodes.length > 0)
{
removeCanvas.removeChild(removeCanvas.firstChild);
}
var newObj = document.createElement('img');
newObj.setAttribute('src', pic.src);
removeCanvas.insertBefore(newObj, removeCanvas.firstChild);
}
}

addEvent(window, 'click', biggerPicture);
The AddEvent function is an event listener...in this case it listens to click events and starts the biggerPicture function - this function checks whether the clicked object is an image and proceeds to do its thing in the case this is true. It does nothing if the object is not an image. Plain img tag images work, e.g.



<html>
<head>
<title>Image test</title>
<script type="text/javascript" src="imagetest.js"></script>
</head>

<body>
<img src="image1.jpg" height="50" />

<p> This image is in a paragraph and it can still be found.<br />
<img src="anotherimage.png" height="50" />
</p>

<img src="yetanotherpicture.gif" height="50" />

<div id="biggerPicture"></div>

<p>
Oh, look! Another image!<br />
<img src="past.png" height="50" />
</p>

</body>
</html>
The contents of imagetest.js is the Javascript code block above the HTML code block. This should work, as far as I can tell - regardless of where the image is in the page. If you have questions about this piece of uh...work, I'll try to answer them. :)

maclenin
January 24th, 2012, 08:46 PM
sh228!

Thanks for your reply.

Is your suggestion...


.setAttribute("onclick", "larger_image(sub_Array[i])");

..."functionally" similar to...


.onclick=function() {larger_image(sub_Array[i]);};

...?

I have a sneaking suspicion a "closure" intervention might be required....


Dimarchi!

Thank you for laying it all out! I will sift through and report / query back! I appreciate the time you're spending to try and help me out of my bind!

maclenin
January 25th, 2012, 02:06 PM
SOLVED!

Closure, indeed!

Here's the "solution":


for (i=0; i<=slen; i++)
{
var id=i;
var Lg=sub_Array[i];
document.getElementById(alpha+"_tLarge"+id).onclick=(function(Lg){
return function(){
large_image(Lg);
};
})(Lg);
}
}

Not that I can thoroughly explain what's happening here to a 6 year old (let alone to myself)...however, my sense is that the "function(Lg) {return function()" sequence encloses/captures/grabs single iterative values of "i" - or in my case the return values of sub_Array[i] as var Lg - over the course of the loop cycle, allowing these single values to be uniquely associated with (and utilized by) their respective "onlcikable" elements through "large_image(Lg)"....

Thanks, first, to you folks for taking the time to toss your ideas and code my way...

Dimarchi!
simeon87!
sh228!

...and to these closure explications...

closures1 (http://trephine.org/t/index.php?title=JavaScript_loop_closures)
closures2 (http://james.padolsey.com/javascript/closures-in-javascript/)

...that pushed me towards a working model.