www.webdeveloper.com
Recent Articles
  • Finding Slow Running Queries in ASE 15
  • A More Advanced Pie Chart for Analysis Services Data
  • Adobe AIR Programming Unleashed: Working with Windows
  • Performance Testing SQL Server 2008's Change Data Capture Functionality
  • The ABC's of PHP: Introduction to PHP
  • How to Migrate from BasicFiles to SecureFiles Storage
  • Why the Twitter Haters Are Wrong
  • User Personalization with PHP: Beginning the Application
  • Whats in an Oracle Schema?
  • Lighting Enhancement in Photoshop
  •  

    Go Back   WebDeveloper.com > Client-Side Development > JavaScript

    JavaScript JavaScript (not Java) Discussion and technical support, including AJAX and frameworks (JQuery, MooTools, Prototype...)

    Reply
     
    Thread Tools Search this Thread Rate Thread Display Modes
      #1  
    Old 06-25-2008, 11:00 AM
    perlmonk perlmonk is offline
    Registered User
     
    Join Date: Jun 2008
    Posts: 13
    javascript closure not working

    Hi All

    I tried the following code
    Code:
      window.onload = function() 
         {
           var list = ['abc', 'xyz'] ; // id's from links
           for(var i = 0; i < list.length; i++ )
            {
              var id = list[i] ;
              document.getElementById(list[i]).onclick = function() { alert("link with id=" + id) }
            }
         }
    Also
    Code:
    document.getElementById(list[i]).onclick = function() { alert("link with id=" + list[i]) }
    doesn't work

    So, when I click on the link with id 'abc' I get the alert showing "link with id=xyz"
    For some reason the closure only memorizes the last values! (and also doesn't remember list)


    Any ideas ?

    thnx in advance
    LuCa

    Last edited by Kor; 06-25-2008 at 11:05 AM. Reason: wrap the code [code][/code]
    Reply With Quote
      #2  
    Old 06-25-2008, 11:11 AM
    Kor's Avatar
    Kor Kor is offline
    Red Devil Moderator
     
    Join Date: Dec 2003
    Location: Bucharest, ROMANIA
    Posts: 11,017
    Why not simply return the element's id on using the self reference this?
    Code:
    for(var i = 0; i < list.length; i++ )
            {
              document.getElementById(list[i]).onclick = function() { alert("link with id=" + this.id) }
            }
    On the other hand, if you need to use the increment [i], you must know that it is an independent variable and it will take, inside the closure, its last value after the loop is finished. A solution is to stick that value of the increment as a custom property of the element:
    Code:
    for(var i = 0; i < list.length; i++ )
    {
    var d=document.getElementById(list[i]);
    d.indexV=i;
    d.onclick = function() { alert("link with id=" + this.indexV) }
    }

    Last edited by Kor; 06-25-2008 at 11:14 AM.
    Reply With Quote
      #3  
    Old 06-25-2008, 11:20 AM
    perlmonk perlmonk is offline
    Registered User
     
    Join Date: Jun 2008
    Posts: 13
    thnx, so this means that javascript doesn't do closures, you just need to stick all the variables in the object itself!
    Reply With Quote
      #4  
    Old 06-25-2008, 11:26 AM
    Kor's Avatar
    Kor Kor is offline
    Red Devil Moderator
     
    Join Date: Dec 2003
    Location: Bucharest, ROMANIA
    Posts: 11,017
    You need to stick only the variables which depends of the increment in a loop. As I said, in a closure, the increment will always take its last value of the loop, because the loop code ends before the closure has the chance to be active. I think this is true in all the languages which uses closures.

    Last edited by Kor; 06-25-2008 at 11:29 AM.
    Reply With Quote
      #5  
    Old 06-26-2008, 03:54 AM
    perlmonk perlmonk is offline
    Registered User
     
    Join Date: Jun 2008
    Posts: 13
    Here is a perl example which shows that you can do what I want:

    #! /usr/bin/perl -l

    my @array ;
    {
    my @vals = qw(a b c d e) ;
    foreach(0..4)
    {
    my $inp = $vals[$_] ;
    my $i = $_ ;
    $array[$_] = sub { print "i = " . $i . " and val = " . $inp . " from ".$vals[$i] } ;
    }
    }

    $array[0]() ;
    $array[3]() ;


    prints:
    i=0 and val = a from a
    i=3 and val = d from d
    Reply With Quote
      #6  
    Old 06-26-2008, 04:22 AM
    Orc Scorcher Orc Scorcher is offline
    S.P.Q.R.
     
    Join Date: Mar 2005
    Posts: 767
    That is because you're using block-scoped variables in your Perl example but function-scoped variables in your JavaScript example. Block-scoped variables were added to JavaScript in version 1.7, try the following example in Fx3:
    Code:
    <script type="text/javascript;version=1.8">
    
    function test() {
    	var chars = "abcde"
    	var funcs = []
    	for (let _ = 0; _ < 5; ++_) {
    		let i = _
    		let val = chars[i]
    		funcs[i] = function () "i = " + i + " and val = " + val + " from " + chars[i]
    	}
    	return funcs
    }
    
    var f = test()
    document.write(f[0](), "<br>", f[3]())
    
    </script>
    __________________
    Stop thinking, start drinking.
    Reply With Quote
      #7  
    Old 06-26-2008, 04:47 AM
    romo romo is offline
    Registered User
     
    Join Date: Jun 2008
    Posts: 5
    You simply don't use closure, use this code instead:
    Code:
      window.onload = function() 
         {
           var list = ['abc', 'xyz'] ; // id's from links
           for(var i = 0; i < list.length; i++ ) new function()
            {
              var id = list[i] ;
              document.getElementById(list[i]).onclick = function() { alert("link with id=" + id) }
            }
         }

    Last edited by romo; 06-26-2008 at 04:54 AM.
    Reply With Quote
      #8  
    Old 06-26-2008, 04:52 AM
    Kor's Avatar
    Kor Kor is offline
    Red Devil Moderator
     
    Join Date: Dec 2003
    Location: Bucharest, ROMANIA
    Posts: 11,017
    Oh, I see. Well, yes, in javascript you may do that this way:
    Code:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <title>untitled</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <script type="text/javascript">
    var array;
    var vals=['a','b','c','d','e'];
    var inp;
    for(var i=0;i<=4;i++){
    window['array']=function(i){
    inp=vals[i];
    var d=document.getElementById('mydiv');
    var inTxt=d.innerHTML+'i ='+i+' and val = '+inp+' from '+vals[i]+'<br>';
    d.innerHTML=inTxt;
    }
    }
    onload=function(){
    array(0);
    array(3);
    }
    </script>
    </head>
    <body>
    <div id="mydiv"></div>
    </body>
    </html>
    But here you are dealing with global variables (global scope) not with local variables (function scope). In your first example your variables were local, thus the closure cold not keep them.

    Last edited by Kor; 06-26-2008 at 04:56 AM.
    Reply With Quote
      #9  
    Old 06-26-2008, 06:50 AM
    Logic Ali's Avatar
    Logic Ali Logic Ali is offline
    Just don't say "menu"
     
    Join Date: Mar 2007
    Location: U.K.
    Posts: 606
    Quote:
    Originally Posted by romo
    You simply don't use closure, use this code instead:
    Code:
      window.onload = function() 
         {
           var list = ['abc', 'xyz'] ; // id's from links
           for(var i = 0; i < list.length; i++ ) new function()
            {
              var id = list ;
    [i]          document.getElementById(list).onclick = function() { alert("link with id=" + id) }
           }
        }
    [i]
    That code is forming closures. The new operator just has the effect of executing the function, instead of calling it like this:
    Code:
     
    for(var i = 0; i < list.length; i++ ) 
    (function() 
    {
     var id = list[i] ;
     document.getElementById(list[i]).onclick = function() { alert("link with id=" + id) }
    })();
    __________________
    If DynamicDrive was the answer, it must have been a funny question.

    Code:
    answer = question.match(/back button|calendar|calculator|coundown timer|dynamic\s?drive|hangman|jquery|lightbox|menu|right-click|sniffer|snowflake/) ? "Dream-on sucker" : "Maybe...";
    Reply With Quote
      #10  
    Old 06-26-2008, 08:25 AM
    forty2 forty2 is offline
    Registered User
     
    Join Date: Oct 2006
    Posts: 108
    Or like this:
    Code:
    window.onload = function()
    {
    	var o_links = document.getElementsByTagName('a');
    	for (var i = 0, len = o_links.length; i < len; i++)
    	{
    		o_links[i].onclick = function(sender_num)
    		{
    			return function()
    			{
    				alert(sender_num);
    			}
    		}(i);
    	}
    }
    Reply With Quote
      #11  
    Old 06-26-2008, 08:59 AM
    Kor's Avatar
    Kor Kor is offline
    Red Devil Moderator
     
    Join Date: Dec 2003
    Location: Bucharest, ROMANIA
    Posts: 11,017
    There are a lot of ways to skin a cat
    Reply With Quote
      #12  
    Old 06-28-2008, 11:03 AM
    perlmonk perlmonk is offline
    Registered User
     
    Join Date: Jun 2008
    Posts: 13
    thnx a lot!!!
    Reply With Quote
      #13  
    Old 07-19-2008, 08:15 PM
    cooper.semantic cooper.semantic is offline
    Registered User
     
    Join Date: Jul 2008
    Posts: 9
    Hey guys,
    I'm having an issue figuring this out. I have read through this forum but still am running into a spike. If someone could help I would be greatly thankful.

    Here is the javascript:
    function init() {
    var first = getElementsByClass(document, "first", "*");
    for (var i=0; i < first.length; i++) {
    var list = first[i]
    list.onclick = (function() {
    return function() {
    var last = getElementsByClass(document, "last", "*")[0];
    toggle(last);
    };
    })();
    }
    }

    function toggle(ob) {
    if (ob.style.display == "block") {
    ob.style.display = "none";
    }
    else { ob.style.display = "block"; }
    }

    Here is the HTML:
    <ul>

    <li class="first">First</li>
    <li style="display: none;" class="last">Last</li>

    <li class="first ">First</li>
    <li style="display: none;" class="last ">Last</li>

    <li class="first ">First</li>
    <li style="display: none;" class="last ">Last</li>
    </ul>

    Last edited by cooper.semantic; 07-19-2008 at 08:31 PM.
    Reply With Quote
      #14  
    Old 07-19-2008, 08:43 PM
    Declan1991 Declan1991 is offline
    Moderator
     
    Join Date: Aug 2007
    Posts: 2,694
    You should start your own thread in future.
    If they are every second turn like that, JavaScript is capable of figuring that out, you don't need all the classes.

    Code:
    function init() {
    	var li = document.getElementById("list").getElementsByTagName("li");
    	for (var i = 0; i < li.length; i+=2) {
    		li[i].onclick = (function() {
    			var last = li[i+1], shown = false;
    			last.style.display="none";
    			return function() {
    				last.style.display = shown?"none":"block";
    				shown = !shown;
    			};
    		})();
    	}
    }
    Code:
    <ul id="list">
    
    <li>First</li>
    <li>Last</li>
    
    <li>First</li>
    <li>Last</li>
    
    <li>First</li>
    <li>Last</li>
    </ul>

    The fix to your code would be
    Code:
    function init() {
    var first = getElementsByClass(document, "first", "*");
    var lasts = getElementsByClass(document, "last", "*");
    for (var i=0; i < first.length; i++) {
    var list = first[i]
    list.onclick = (function() {
    var last = lasts[i];
    return function() {
    toggle(last);
    };
    })();
    }
    }
    __________________
    If I have helped
    Quote:
    Great wit and madness are near allied, and fine a line their bounds divide.

    Last edited by Declan1991; 07-19-2008 at 09:00 PM.
    Reply With Quote
      #15  
    Old 07-19-2008, 09:05 PM
    cooper.semantic cooper.semantic is offline
    Registered User
     
    Join Date: Jul 2008
    Posts: 9
    I see where I went wrong. I did not want to start my own thread with the same topic. I figured since this was an already established thread with my same problem it would be just fine. I thank you though for helping me out.
    Reply With Quote
    Reply

    Bookmarks


    Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
     
    Thread Tools Search this Thread
    Search this Thread:

    Advanced Search
    Display Modes Rate This Thread
    Rate This Thread:

    Posting Rules
    You may not post new threads
    You may not post replies
    You may not post attachments
    You may not edit your posts

    BB code is On
    Smilies are On
    [IMG] code is Off
    HTML code is Off
    Forum Jump


    All times are GMT -5. The time now is 01:02 AM.



    Acceptable Use Policy

    internet.comMediabistrojusttechjobs.comGraphics.com

    WebMediaBrands Corporate Info


    Advertise | Newsletters | Feedback | Submit News

    Legal Notices | Licensing | Reprints | Permissions | Privacy Policy

    Powered by vBulletin® Version 3.7.3
    Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.