In your code:
> if (daform.multi.length == undefined) {
if multi is the name of all the checkboxes, then dataform.multi
will return either:
- one element if there's only one form control named multi
- an HTML collection of all the form controls named multi if there's more than one
undefined
if there are no elements with a name of multi (and no form properties of that name).
So the only case that the above test will "work" is in #2. In #3 it will throw an error.
Much better to do:
var multis = daform.multi; // might be a collection, DOM element or undefined
if (typeof multis != 'undefined') { // might be a collection or DOM element
if (multis.tagName) {
// dealing with an element
} else {
// dealing with a collection
}
} else {
// there are no form controls named multi
}
Anyhow, consider instead putting a single click listener on the form. If it gets a click from a checkbox named 'multi', and it's checked, add one to a "checked" varable. If it's not checked, subract one. e.g.
<form name="daform" onclick="countCheckedMultis(event);">
<input type="checkbox" name="multi" value="...">
<input type="checkbox" name="multi" value="...">
<input type="checkbox" name="multi" value="...">
</form>
and the function:
var countCheckedMultis = (function() {
// Keep running total in a closure ("private" member)
var numberChecked = 0;
return function (evt) {
var el = evt.target || evt.src;
// Deal with case where target isn't an element node
if (el.nodeType != 1) el = el.parentNode;
// Increment or decrement counter if came from multi element
// depending on if it's checked or not
if (el.name == 'multi') numberChecked += el.checked? 1 : -1;
// Debug
alert(numberChecked);
}
}());
The flaw in the above is that if the page is refreshed, some browser will keep all the checked checkboxes checked, but reset the counter. So you need to initialise the counter on the first click.
Note that the collection returned by daform.multi
is converted to an array before processing. This hugely increases performance, looping over 10,000 checkboxes takes less than a second in Firefox 15, Chrome 22 and IE 9 on a modest PC.
// Convert obj to array (simple function for this case)
function toArray(obj) {
var result = [];
for (var i=0, iLen=obj.length; i<iLen; i++) {
result[i] = obj[i]
}
return result;
}
var countCheckedMultis = (function() {
var initialised;
var numberChecked = 0;
return function (evt) {
var el = evt.target || evt.src;
if (el.nodeType != 1) el = el.parentNode;
// If this is the first run, need to count checked checkboxes
// as page may have been reloaded, resetting the counter but not
// the checked checkboxes in some browsers
if (!initialised && el.form) {
var multis = el.form.multi;
// Converting a collection to an array before processing
// hugely increases speed
if (multis && !multis.tagName) {
multis = toArray(multis);
for (var i=0, iLen=multis.length; i<iLen; i++) {
if (multis[i].checked) ++numberChecked;
}
}
initialised = true;
} else {
if (el.name == 'multi') numberChecked += el.checked? 1 : -1;
}
console.log(numberChecked);
}
}());
onchange
event instead since there might be other ways for the user to check the checkbox other than clicking (i.e. keyboard). \$\endgroup\$