SitePoint Sponsor

User Tag List

Results 1 to 7 of 7
  1. #1
    SitePoint Guru Dashman's Avatar
    Join Date
    Jan 2006
    Location
    Manchester, UK
    Posts
    627
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Checkbox onclick

    Hi guys, sorry, I couldnt think of a better name for the title of this post.
    I have the following function:
    HTML Code:
        var theChecks = document.getElementsByTagName('input');
        var i;
        for(i = 0; i < theChecks.length; i++)
        {    
            if(theChecks[i].type == "checkbox")
            {
                var thisCheck = theChecks[i];
                thisCheck.onclick = function()
                {
                    if(thisCheck.checked){
                        alert("checked");
                    }
                    else
                    {
                        alert("unchecked");
                    }            
                }                
            }            
        }
    What I am ultimately trying to achieve, is run a function when the checkbox is first checked, and then run a different function when the same checkbox is unchecked. At the moment, the "unchecked" alert shows on check AND uncheck.

    Could somebody please let me know what I am doing wrong in the code ?

    D

  2. #2
    CSS & JS/DOM Adept bronze trophy
    Join Date
    Mar 2005
    Location
    USA
    Posts
    5,482
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Does the same thing happen when you click on the last checkbox?
    We miss you, Dan Schulz.
    Learn CSS. | X/HTML Validator | CSS validator
    Dynamic Site Solutions
    Code for Firefox, Chrome, Safari, & Opera, then add fixes for IE, not vice versa.

  3. #3
    SitePoint Evangelist dmsuperman's Avatar
    Join Date
    Feb 2005
    Location
    A box
    Posts
    516
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Try replacing
    Code:
                    if(thisCheck.checked){
    with
    Code:
                    if(this.checked){
    Perhaps there's a problem with using that function's variable inside the onClick function. I'm thinking that the function will run independently of your piece of code, in which case thisCheck would no longer exist, or at least be set as the last checkbox on the page (ie the last one in the loop).
    <(^.^<) \(^.^\) (^.^) (/^.^)/ (>^.^)>
    Core 2 Duo E8400 clocked @ 3.375GHz, 2x2GB 800MHz DDR2 RAM
    5x SATA drives totalling 2.5TB, 7900GS KO, 6600GT

  4. #4
    SitePoint Enthusiast
    Join Date
    Mar 2007
    Posts
    25
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by dmsuperman View Post
    Try replacing
    Code:
                    if(thisCheck.checked){
    with
    Code:
                    if(this.checked){
    Perhaps there's a problem with using that function's variable inside the onClick function. I'm thinking that the function will run independently of your piece of code, in which case thisCheck would no longer exist, or at least be set as the last checkbox on the page (ie the last one in the loop).
    This definitely is a fix but I'm not satisfied with the explanation .

    If anyone's wondering how badly I need to get some sleep: I spent 45 minutes working with this problem and following a trail of prior solutions.

    Here's the solution:

    General notes:

    1) The first note is that for this particular situation, using 'this' works well. It wasn't necessary to define a variable outside of the anonymous function.

    2) In cases where it is necessary to define a variable outside the function and access it within, this might be useful.

    Obligatory preface:

    JavaScript supports a powerful feature known as closures. This simply means that a function is bounded to its lexical environment. In other words, a function knows about the variables outside its scope.

    Back to the show:

    So in this case, the anonymous function does know about thisCheck. Try it for yourself by alerting thisCheck. Or better yet, assign an ID to each checkbox, and then alert the ID. You'll see that the last checkbox is alerted each time.

    So what's the problem? When JavaScript is forming the closure between the event handler and thisCheck, it is only saving the -reference- to thisCheck. It isn't copying the value.

    This means, that each of your checkboxes hold their own references to the same value.

    How can this be solved? You need to save a new copy of thisCheck to each new event handler.

    Here's how you do it:

    Code:
    var theChecks = document.getElementsByTagName('input');
    var i;
    for(i = 0; i < theChecks.length; i++) {    
    	if(theChecks[i].type == "checkbox") {
    		var thisCheck = theChecks[i];
    		thisCheck.onclick = (function() {
    			var saveCheck=thisCheck;
    			return function() {
    				if (saveCheck.checked) {
    					alert("checked");
    				} else {
    					alert("unchecked");
    				}            
    			}
    		})();
    	}            
    }
    The basic idea is that we are creating a function that returns a function... which is executed immediately. Within the function we are creating a new reference to thisCheck as saveCheck, and then a closure is formed between the new reference and the inner inner function. Because saveCheck is a local variable to a newly created function, there is a new thisCheck reference for each function. The code should work.

    Again, is this worth the effort? Absolutely not. Could it be useful in another situation? Sure

    Some of my research and good reading to fully understand the problem (the simplest problems can be deceiving):

    About the closure "gotcha"
    A similar problem
    The original link. Note: The author's reasoning isn't correct. The other articles explain this further.

    Happy coding.

  5. #5
    SitePoint Guru Dashman's Avatar
    Join Date
    Jan 2006
    Location
    Manchester, UK
    Posts
    627
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Synotic, that you very much for your detailed explanation, although Supermans suggestion actually works perfectly for me. Superman, thanks!

  6. #6
    CSS & JS/DOM Adept bronze trophy
    Join Date
    Mar 2005
    Location
    USA
    Posts
    5,482
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    synotic, so it took you less than an hour to figure out closures? Congratulations. This is indeed a common problem.

    I was going to use my question as a lead in to posting a link to an explanation of them, e.g. http://blog.morrisjohns.com/javascri...s_for_dummies/.
    We miss you, Dan Schulz.
    Learn CSS. | X/HTML Validator | CSS validator
    Dynamic Site Solutions
    Code for Firefox, Chrome, Safari, & Opera, then add fixes for IE, not vice versa.

  7. #7
    SitePoint Enthusiast
    Join Date
    Mar 2007
    Posts
    25
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Kravvitz View Post
    synotic, so it took you less than an hour to figure out closures? Congratulations. This is indeed a common problem.

    I was going to use my question as a lead in to posting a link to an explanation of them, e.g. http://blog.morrisjohns.com/javascri...s_for_dummies/.
    Kravvitz: No. I thought I already understood them, but I didn't realize that it was merely the variables/references that were being bound to the scopes. Which in retrospect makes perfect sense and solves a lot of the problems I've been having. Shows that you are always learning. I'll take a look at your link.

    Also, if anyone wants a marathon-of-an-article about closures that will leave you out of breath: JavaScript closures by Richard Cornford. It goes deep down and shows the beauty of how everything in JavaScript really is an object and how closures are really concrete objects that are properties ([[scope]]) of their functions/execution contexts.


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
  •