views:

210

answers:

5

I have a form with thousands of checkboxes, and when one is checked, I want to check all the boxes below it. This works:

<html>
<body>
<form name="myform">
<input type="checkbox" name="box1" onClick="redrawboxes(this);">1<br>
<input type="checkbox" name="box2" onClick="redrawboxes(this);">2<br>
...
</form>
</body>
</html>
<script>
function redrawboxes(obj){  
    //check all boxes below 
    var foundit=false;
    for (e=0; e<document.myform.elements.length; e++){
     if (foundit==false){ //search for checked obj
      if(obj == document.myform.elements[e]){ 
       foundit=true;  
      }
     }else{ //continuing below checked box
      if(obj.checked){ //are we checking or unchecking
        document.myform.elements[e].checked = true;
      }else{
        document.myform.elements[e].checked = false;
      }
     }
    }
}
</script>

but for more than a few thousand boxes, IE is unacceptably slow. (Firefox works fine.) Is there a better way to find the original box besides iterating through the whole list?

+3  A: 

i might get down voted for this, but try using jquery. it has selectors optimized for that.

01
+2  A: 

Advertising inside !

If you are using jQuery, you can try my plugin to make your loop asynchronous, this will allow to run a long loop without freezing the browser.

http://mess.genezys.net/jquery/jquery.async.php

If you don't want to use jQuery, you can download the plugin and modify the code for your own needs, it does not really depend on jQuery.

Vincent Robert
+2  A: 

You can read out the name of the selected checkbox like this:

function redrawboxes(obj) {
    var name = obj.name;
    var state = obj.checked;

    // get that index
    var index = name.substr(3) * 1; // just to be sure it's a number
    var length = document.myform.elements.length;
    var allElements = document.myform.elements

    // (un)check all elements below
    for (var i = index; i < length; i++) {
        allElements[i].checked = state;
    }
}

You could have sped up your code quite a bit by using local variables and there's an if-statement that can be replaced.

Edit: Actually that one-off-error isn't an error because that specific checkbox was (un)checked by the user himself.

Georg
You have an off-by-one error (since his numbering starts with 1). More seriously, this code won't let you uncheck a box by clicking it. And it unchecks every box above the one you clicked.
Shog9
The off-by-one is my mistake :) The other I've corrected 7 minutes ago. And thanks for the last one, that command is not needed for the code at all, removed it.
Georg
Much better - and slightly faster than mine! :-)
Shog9
That is a very fast method to solve the problem I posed. In my real code, I can't use the name of the field as an index because of the structure of the data, but I did pick up some pointers, like not testing it obj is checking in a loop (duh). Thank you.
Jon Wilson
+4  A: 

Both of the jQuery suggestions are pretty good. For DOM wrangling like this, you're really better off using a good library.

And the comment about the dubious wisdom of putting thousands of checkboxes on a form is pretty good as well...

But, on the off-chance that you do have a good reason for doing this, and you can't use jQuery or similar, here's a fast, straight JS method:

function redrawboxes(obj)
{  
    //check all boxes below     
    var next = obj;
    while ( (next = next.nextSibling) )
    {
      if ( next.nodeName.toLowerCase() == "input" 
        && next.type.toLowerCase() == "checkbox" )
        next.checked = obj.checked;
    }
}

tested in FF3, FF3.1, IE6, Chrome 1, Chromium 2

Shog9
Maybe one should compare the tagName using a case insensitive method or leave the comparison out if one knows that there are only checkboxes. (As the solution of the asker suggests.)
Georg
@gs: nextSibling will pick up all sorts of nodes, not just HTML elements. So even if there are only checkbox fields on the form, we still need to skip past the text nodes.
Shog9
...as for the tag name comparison, it won't matter for HTML but it's probably a good idea just to be safe if used in XHTML - i'll update it.
Shog9
@Shog9: there's something new to learn every day :)
Georg
+2  A: 

Dunno how fast it is, but you could try the jQuery-way, grab jQuery from www.jquery.com and insert the following code on the page:

$(function(){
    $("input:checkbox").click(function(){
        $(this).nextAll("input:checkbox").each(function(){
            this.checked = true;
        });
    });
});
svinto