Results 1 to 7 of 7

Thread: Simplifying some code.

  1. #1
    Join Date
    Apr 2006
    Posts
    205
    Thanks
    11
    Thanked 0 Times in 0 Posts

    Smile Simplifying some code.

    Hi,

    I've written some functions to display and not display things.

    Code:
    function displayBlock(elementName) {
    	
    	obj = document.getElementById(elementName);
    	obj.style.display="block";
    }
      
    function displayNone(elementName) {
    
    obj = document.getElementById(elementName);
    obj.style.display="none";
    }
    I want to use the code to display a large image when the user clicks on a thumbnail and hide all the other large images.

    Here's an example of how I'm writing the HTML when dealing with just three images and it's already getting a bit much to define all the images I don't want to display.
    HTML Code:
    <div id="thumbnails">
      <a href="javascript:displayBlock('img1'); displayNone('img2'); displayNone('img3');"><img src="thumb1.jpg" /></a>
      <a href="javascript:displayBlock('img2'); displayNone('img1'); displayNone('img3');"><img src="thumb2.jpg" /></a>
      <a href="javascript:displayBlock('img3'); displayNone('img1'); displayNone('img2');"><img src="thumb3.jpg" /></a>
    </div>
    
    <div id="largeImage">
      <div id="img1">
        <img src="img1.jpg" />
      </div>
      <div id="img2">
        <img src="img2.jpg" />
      </div>
      <div id="img3">
        <img src="img3.jpg" />
      </div>
    </div>
    Can someone help me modify my code so rather than saying, 'Show this and don't show that, that or that' I can just say, 'Show this and don't show anything else.'?

    Thanks for any responses.

    Dog

  2. #2
    Join Date
    May 2007
    Location
    USA
    Posts
    373
    Thanks
    2
    Thanked 4 Times in 4 Posts

    Default

    Code:
    <div id="thumbnails">
      <a href="javascript:void(0);"><img src="thumb1.jpg" /></a>
      <a href="javascript:void(0);"><img src="thumb2.jpg" /></a>
      <a href="javascript:void(0);"><img src="thumb3.jpg" /></a>
    </div>
    
    <div id="largeImage">
      <div id="img1">
        <img src="img1.jpg" />
      </div>
      <div id="img2">
        <img src="img2.jpg" />
      </div>
      <div id="img3">
        <img src="img3.jpg" />
      </div>
    </div>
    
    <script type="text/javascript">
    (function() {
    	var thumbs = document.getElementById("thumbnails").getElementsByTagName("a");
    	var largeImgs = document.getElementById("largeImage").getElementsByTagName("div");
    	var n = thumbs.length;
    	function toggle(x) {
    		for(var i=0; i<n; ++i)
    			if(i!=x) largeImgs[i].style.display = "none";
    			else largeImgs[i].style.display = "block";
    		}
    	for(var i=0; i<n; ++i)
    		if(document.addEventListener)
    			thumbs[i].onclick = (function() {
    				var x = i;
    				return function(e) {
    					toggle(x);
    					};
    				})();
    	})();
    </script>
    Trinithis

  3. #3
    Join Date
    Apr 2006
    Posts
    205
    Thanks
    11
    Thanked 0 Times in 0 Posts

    Smile

    Hey Trinithis,

    Thanks for the code. I've tried putting it in place but so far I'm not getting any results at all.

    How does the function get called? What does "javascript:void(0);" do?

    I just noticed that in my original post I didn't define the CSS I was using to hide the large images. Here's a copy of the whole page.

    HTML Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>Test 1b</title>
    
    <script type="text/javascript">
    function displayBlock(elementName) {
    	
    	obj = document.getElementById(elementName);
    	obj.style.display="block";
    }
      
    function displayNone(elementName) {
    
    obj = document.getElementById(elementName);
    obj.style.display="none";
    }
    </script>
    
    <style type="text/css">
    #thumbnails img { width: 74px; height: 44px; }
    #img2, #img3 { display: none; }
    </style>
    
    </head>
    
    <body>
    
    <div id="thumbnails">
      <a href="javascript:displayBlock('img1'); displayNone('img2'); displayNone('img3');"><img src="../img/74x44/pedro_1.jpg" /></a>
      <a href="javascript:displayBlock('img2'); displayNone('img1'); displayNone('img3');"><img src="../img/74x44/pedro_2.jpg" /></a>
      <a href="javascript:displayBlock('img3'); displayNone('img1'); displayNone('img2');"><img src="../img/74x44/pedro_3.jpg" /></a>
    </div>
    
    <div id="largeImage">
      <div id="img1" >
        <img src="../img/350/pedro_1.jpg" width="250" height="158" />
      </div>
      <div id="img2">
        <img src="../img/350/pedro_2.jpg" width="250" height="178" />
      </div>
      <div id="img3">
        <img src="../img/350/pedro_3.jpg" width="350" height="261" />
      </div>
    </div> 
         
    </body>
    </html>
    The effect I'm looking for is:

    When the user clicks on thumbnail 2 for example, 'img2' gets display and all the other divs inside the largeImages div get set to not display. In the code above it's working. In the real site there are many, many images so I want a way to reduce:
    Code:
    displayBlock('img1'); displayNone('img2'); displayNone('img3');
    into
    Code:
    displayBlock('img1'); displayNoneEverythingExcept('img1');
    I liked the bit of your code where you defined the variables 'thumbs' and 'largeImgs':
    Code:
    var thumbs = document.getElementById("thumbnails").getElementsByTagName("a");
    var largeImgs = document.getElementById("largeImage").getElementsByTagName("div");
    I didn't know how to identify all the elements of a div like that. What you did after that I don't understand.

    Thanks agains for the help.

    Peace!
    Dog

  4. #4
    Join Date
    May 2007
    Location
    USA
    Posts
    373
    Thanks
    2
    Thanked 4 Times in 4 Posts

    Default

    Oops, I forgot to take out the if(document.addEventListener). That would cause problems in IE.
    The code should be
    Code:
    (function() {
    	var thumbs = document.getElementById("thumbnails").getElementsByTagName("a");
    	var largeImgs = document.getElementById("largeImage").getElementsByTagName("div");
    	var n = thumbs.length;
    	function toggle(x) {
    		for(var i=0; i<n; ++i)
    			if(i!=x) largeImgs[i].style.display = "none";
    			else largeImgs[i].style.display = "block";
    		}
    	for(var i=0; i<n; ++i)
    		thumbs[i].onclick = (function() {
    			var x = i;
    			return function(e) {
    				toggle(x);
    				};
    			})();
    	})();
    javascript:void(0) means do nothing and return nothing.


    Now an explanation:

    Code:
    for(var i=0; i<n; ++i)
    	thumbs[i].onclick = (function() { 
    		var x = i;
    		return function(e) {
    			toggle(x);
    			};
    		})();
    This sets up a loop that iterates n times, where n is defined above as thumbs.length.
    Then for each element in thumbs, thumbs[i], I tell it to react to a user's click, via onclick.
    Now I need to explain something that might be a little confusing:

    Code:
    var myFunc = function(){something};
    This creates a function that does something when activated, aka, through myFunc();

    Now if you did:
    Code:
    function(){something};
    This creates a function that would do something if activated. But the question is how? It is not attached to a variable such as myFunc. This is called an anonymous function. It has no name.
    However, there are uses for them even if you can't call them whenever you want.

    One thing to notice is that if you take the variable a function is stored in, you could do this:
    Code:
    (myFunc)();
    This is equivalent to:
    Code:
    myFunc();
    This is analogous to parenthesis around numbers:
    Code:
    5+4
    (5+4)
    (5)+4
    All these do the same thing.

    To understand why this works with functions requires an understanding of variable references. For example:
    Code:
    var func1 = function(){ alert('hi'); };
    var func2 = func1;
    The above code creates two variables, func1 and func2, but there is only one function. When you do
    Code:
    var func2 = func1;
    you are not copying the entire function(){alert('hi');} into func2... only references to it. Rather when you do
    Code:
    var func1 = function(){ alert('hi'); };
    Javascript creates a function, function(){alert('hi');}, and stores it in the computer's memory somewhere. Then when the assignment happens, instead of giving func1 the function, the computer stores into func1 a reference of the function stored in memory.
    In other words, the computer tells func1 where to find the function. So when you do
    Code:
    func1();
    the computer asks func1 what is is holding. It finds out it is holding a reference to a function. Then it asks, where is this function located, and func1 returns the actual function. Once returned, the computer takes that function and activates it.

    Anyway, (myFunc)() works because myFunc will return the function, and you can think of it as for a split second, the actual function sits around within those parenthesis before becoming activated via the ().

    The reason why this matters is because you can use this principle with anonymous functions. Say you had the anonymous function:
    Code:
    function(x){ alert(x); }
    And you wanted to execute it immediately, right when you made it.
    You could do
    Code:
    (function(msg){ alert(msg); })("hello");
    Note where the "hello" is. Just like a normal function, you still have to supply arguments, in this case, for msg.
    Now, you might be wondering what the point of creating a one-time function and executing it immediately. Why not write the code outside of a function if you are going to do that?
    The key is that functions create their own scope, meaning variables made inside it are only known to the function. This means the outside world can't change what's happening inside it.

    So in my code I do:
    Code:
    (function() { 
    	var x = i;
    	return function(e) {
    		toggle(x);
    		};
    	})();
    First I created an anonymous function and immediately execute it once made. Inside the function, I make a variable called x and assign it the value i.
    While x cannot be seen from the outside, the function can see variables that are outside it (to a certain extent). So it knows i.
    Then it creates a function
    Code:
    function(e) { toggle(x); };
    and returns the reference of that function via the return keyword to thumbs[i].onclick.
    A useful thing about Javascript is that it allows something called a closure. I'll get around to that in a sec.

    Normally, when a function is finished executing, all the local variables it creates vanish. However, if you can return something that can reference at least one of those local variables, then the local variables can live beyond the life of their function. At the same time, they are still considered local. Things that were not created in the function still cannot see or touch them.
    In my case, I return a new (and anonymous) function that makes reference to the local variable x. Since this function was returned and therefore can be used outside of the function that created it, and at the same time, it uses the local variable x of it's parent function, x does not die.
    This is the essence of a closure: to make variables that are local within a function, but linger after a function has died.

    Code:
    thumbs[i].onclick = function(e){something};
    Means that whenever that element is clicked, do that function. All functions assigned as events (such as clicking) need the paramater e as their first and only paramater.

    It should be noted that thumbs[i].onclick is assigned a function reference, in this case, the reference of the
    Code:
    function(e) { toggle(x); }
    that was returned.

    Now, all the thumbs[i]'s have been assigned event handlers (function for events). Each of these handlers have their own local variable x that cannot and will not interfere with one another despite having the same name.
    So when clicked, the anonymous function assigned to the onclick will activate toggle(x).

    The function toggle says hide all the images in largeImgs, except for the x'th image (rememeber, there is a 0'th index).

    To tie things up, I wrapped my entire code within an anonymous function that I immediately execute so that you wouldn't get variable name collisions. (Like a self-inclosed namespace.)



    I hope this makes sense
    Last edited by Trinithis; 10-04-2007 at 05:02 PM.
    Trinithis

  5. #5
    Join Date
    Apr 2006
    Posts
    205
    Thanks
    11
    Thanked 0 Times in 0 Posts

    Thumbs up

    Trinithis,

    Thanks so much. Works a treat!

    I can't say I understand everything in the explaination just yet but I really appricate having it.

    This is going to be one thread I come back to again and again.

    I do have one question already. After mistakenly placing the code in the head and then in the body before the HTML I realise the code only works when it comes after the HTML in the body.

    Why is that?

    I'm sure I'll be back with more questions before to long but first I'm going to read over your explaination a few times.

    Thanks again

  6. #6
    Join Date
    May 2007
    Location
    USA
    Posts
    373
    Thanks
    2
    Thanked 4 Times in 4 Posts

    Default

    When you do getElementById("something"), if the code is placed before the element (the tag), then the getElementById thinks the element does not exist. You don't have to place it after the entire body tag... just after the tags it references. getElementsByTagName works similarly.
    Trinithis

  7. #7
    Join Date
    May 2007
    Location
    USA
    Posts
    373
    Thanks
    2
    Thanked 4 Times in 4 Posts

    Default

    Here's a simple demo that might help you understand closures:

    Code:
    var num = 9;
    
    function incrementer() {
    	var num = 0;  //different than the num outside
    	return function() { alert(++num); };
    	}
    
    var x1 = incrementer();
    var x2 = incrementer();
    
    x1();  //alerts 1
    x1();  //alerts 2
    x2();  //alerts 1
    x1();  //alerts 3
    x2();  //alerts 2
    Compared to:
    Code:
    var num = 0;
    
    function incrementer() {
    	return function() { alert(++num); };
    	}
    
    var x1 = incrementer();
    var x2 = incrementer();
    
    x1();  //alerts 1
    x1();  //alerts 2
    x2();  //alerts 3
    x1();  //alerts 4
    x2();  //alerts 5
    The first code example uses a closure. The second does not.
    Last edited by Trinithis; 10-04-2007 at 10:32 PM.
    Trinithis

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •