newbie Javascript checked is null or not an object

S

shall

I have a web page I click on a link which calls AJAX routine to list 3
checkboxes.
I'm trying to use Javascript for a SELECT ALL to select all of the
checkboxes.

The check boxes MUST be in a AJAX routine. My select all function
would work if
the checkboxes were on the same page.
Here is sample code :
======== Below AJAX section ======
<%
response.write "<table border=""1"" width=""80%""
align=""center"">"
response.write "<tr><td colspan=""3"" class=""normalem""
align=""center"">"
response.write "<a href='javascript:selectall(""3"")'>Select all
names</a>"
response.write "</td></tr>"
Response.write "<tr><td align=""center"">"
Response.write "<input type=""checkbox"" id=""oneemp1"" "
Response.write " name=""oneemp"" value=""123"">Chevy<br>"
Response.write "<input type=""checkbox"" id=""oneemp2"" "
Response.write " name=""oneemp"" value=""456"">Ford<br>"
Response.write "<input type=""checkbox"" id=""oneemp3"" "
Response.write " name=""oneemp"" value=""789"">Honda<br>"
Response.write "</td></tr></table>"
%>

====== Below page calling AJAX ==============
<HTML Lang="en">
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<TITLE>Test Ajax</TITLE>
<script language="JavaScript">
function killenter() {
return false;
}
function selectall(myCode) {
intCode=parseInt(myCode);
intMaxLength=document.form1.length;
for( elemnum=0; elemnum<intMaxLength; elemnum++){
var gg=document.form1.elements[elemnum].name;
var strTmp = gg.substring(0,6);
if( strTmp=="oneemp"){
var ff=document.form1.elements[gg][elemnum];
if ( !ff.checked) {
ff.checked=!ff.checked;
}
else{
ff.checked=false;
}
}
}
}

function dView(AA){
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHttp");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{

document.getElementById("listCars").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","TestAjaxCars.asp",true);
xmlhttp.send();
}
</script>
</HEAD>
<body bgcolor="#FFFFFF" text="#000000" link="#800000" vlink="#800000"
alink="#800000">

<div align="center">
</select>&nbsp;&nbsp;<a href='javascript:dView("123")'>Show Cars</a>
</div>
<form name="form1" action="dosomething.asp"
method="post" onSubmit="return killenter()">
<input type="hidden" name="Fyear" value="2012">

<div id="listCars"></div>
</form>

</BODY>
</HTML>

The error message I currently get is :
checked is null or not an object

Suggestions?
TIA
Steve
 
E

Elegie

On 09/11/2011 17:10, (e-mail address removed) wrote :

Hi,

function selectall(myCode) {
intCode=parseInt(myCode);
intMaxLength=document.form1.length;
for( elemnum=0; elemnum<intMaxLength; elemnum++){
var gg=document.form1.elements[elemnum].name;
var strTmp = gg.substring(0,6);
if( strTmp=="oneemp"){
var ff=document.form1.elements[gg][elemnum];

"elemNum" is an iterator over all elements of the FORM, not an iterator
over the elements of the checkbox group. Try and replace the line above by:

var ff=document.form1.elements[elemnum]; // untested
if ( !ff.checked) {
ff.checked=!ff.checked;
}
else{
ff.checked=false;
}

This conditional hurts, because the conditions display different logic.
Why not simply write (if this really is what you want):

ff.checked = !ff.checked;

or (as your title suggests)

ff.checked = true;
Suggestions?

Yes. I'll be blunt here, but your code really needs cleaning up. The
HTML is not validated (there's a "</select>" somewhere), your javascript
is not properly indented, has undeclared variables and so on... Remember
that there's no compiler to help you, so if you start working with
messed up code, then debugging will be increasingly difficult (as you
have experienced).

HTH,
Elegie.
 
D

Denis McMahon

On Wed, 09 Nov 2011 17:59:28 +0100, Elegie wrote:

var ff=document.form1.elements[elemnum]; // untested

/* then wrap the tests so that it only looks for the checked property on
actual checkboxes */

if (ff.type == "checkbox") ff.checked = !ff.checked; // untested

/* or it will barf when you test an element that doesn't have the checked
property. */

(I assume that the OPs intent was to toggle the checkbox state, as that's
what his code was actually doing.)

You could even (and I'm sure someone will shortly post saying why this is
bad, but probably not actually explaining (a) why or (b) the 'proper' way
of doing it) use something like (not tested either):

var inputsInListcarsDiv = document.getElementById
("listcars").getElementsByTagName("input");
for (var i = 0; i < inputsInListcarsDiv.length; i++) if
(inputsInListcarsDiv.type == "checkbox") inputsInListcarsDiv.checked
= !inputsInListcarsDiv.checked;

You could drop the 'if (inputsInListcarsDiv.type == "checkbox")' if
you know for an absolute certainty that all the inputs in that div will
only ever be checkboxes.

Rgds

Denis McMahon
 
T

Thomas 'PointedEars' Lahn

Denis said:
On Wed, 09 Nov 2011 17:59:28 +0100, Elegie wrote:

var ff=document.form1.elements[elemnum]; // untested

/* then wrap the tests so that it only looks for the checked property on
actual checkboxes */

if (ff.type == "checkbox") ff.checked = !ff.checked; // untested

A more reliable test would be

if (typeof ff.checked != "undefined")
{
ff.checked = !ff.checked;
}

That is, you should test the property that you intent to access. But if
this is for checkboxes only, your way should suffice.
/* or it will barf when you test an element that doesn't have the checked
property. */

That is not likely. While host objects do have a reputation for being
unreliable, many of them will allow the addition of new properties, and will
yield the standard `undefined' value when accessing non-existent properties
(and !undefined === true). It is still unreliable, though.

However, this code should never be applied to objects that do not have a
`checked' property in the first place, which renders the question moot and
the test unnecessary.
You could even (and I'm sure someone will shortly post saying why this is
bad,

It is bad,
but probably not actually explaining (a) why

because it is comparably inefficient, incompatible, and unnecessary.
or (b) the 'proper' way of doing it)

The proper way of doing it is described in the FAQ of this newsgroup and
involves the standard backwards-compatible `forms' and `elements'
collections.

Put politely, you would be well-advised to read the FAQ and listen to the
people who very obviously have a lot more experience in this field than you
have.


PointedEars
 
D

David Mark

You could even (and I'm sure someone will shortly post saying why this is
bad, but probably not actually explaining (a) why or (b) the 'proper' way
of doing it) use something like (not tested either):

Sensing some frustration here. :(
var inputsInListcarsDiv = document.getElementById
("listcars").getElementsByTagName("input");
for (var i = 0; i < inputsInListcarsDiv.length; i++) if
(inputsInListcarsDiv.type == "checkbox") inputsInListcarsDiv.checked
= !inputsInListcarsDiv.checked;


For reasons already mentioned (and others), this is bad. I'll add
that this is *really* bad.

You get out of it what you put into it. ;)
 
T

Thomas 'PointedEars' Lahn

Thomas said:
Denis said:
var ff=document.form1.elements[elemnum]; // untested

/* then wrap the tests so that it only looks for the checked property on
actual checkboxes */

if (ff.type == "checkbox") ff.checked = !ff.checked; // untested

[…]
However, this code should never be applied to objects that do not have a
`checked' property in the first place, which renders the question moot and
the test unnecessary.
You could even (and I'm sure someone will shortly post saying why this is
bad,

It is bad,
but probably not actually explaining (a) why

because it is comparably inefficient, incompatible, and unnecessary.

Now as to the why. Remember, the suggested alternative was (formatted):

var inputsInListcarsDiv =
document.getElementById("listcars").getElementsByTagName("input");

for (var i = 0; i < inputsInListcarsDiv.length; i++)
{
if (inputsInListcarsDiv.type == "checkbox")
{
inputsInListcarsDiv.checked = !inputsInListcarsDiv.checked;
}
}

Efficience
-----------

The suggested alternative is comparably inefficient because it requires a
lot more property lookups (P), calls (C) and operations (O). In order of
execution:

P: document
P: document.getElementById
C: document.getElementById("listcars")
P: document.getElementById("listcars").getElementsByTagName
C: document.getElementById("listcars").getElementsByTagName("input");
P: inputsInListcarsDiv
O: inputsInListcarsDiv =
document.getElementById("listcars").getElementsByTagName("input")

`for' statement:

P: i
O: i = 0

inputsInListcarsDiv.length times (any case):

P: i
P: inputsInListcarsDiv
P: inputsInListcarsDiv.length
O: ToBoolean(i < inputsInListcarsDiv.length)
P: inputsInListcarsDiv
P: inputsInListcarsDiv
P: inputsInListcarsDiv.type
O: inputsInListcarsDiv.type == "checkbox"

inputsInListcarsDiv.length times (worst case):

P: inputsInListcarsDiv
P: inputsInListcarsDiv
P: inputsInListcarsDiv.checked
O: !inputsInListcarsDiv.checked
P: inputsInListcarsDiv
P: inputsInListcarsDiv
P: inputsInListcarsDiv.checked
O: inputsInListcarsDiv.checked = !inputsInListcarsDiv.checked

inputsInListcarsDiv.length times (any case):

P: i
O: i++

It is a lot more efficient when written as follows:

var inputsInListcarsDiv =
document.getElementById("listcars").getElementsByTagName("input");

for (var i = inputsInListcarsDiv.length; i--;)
{
var elem = inputsInListcarsDiv;
if (elem.type == "checkbox")
{
elem.checked = !elem.checked;
}
}

Then the following property lookups (P), calls (C) and operations (O) would
take place, in order of execution:

P: document
P: document.getElementById
C: document.getElementById("listcars")
P: document.getElementById("listcars").getElementsByTagName
C: document.getElementById("listcars").getElementsByTagName("input")
P: inputsInListcarsDiv
O: inputsInListcarsDiv =
document.getElementById("listcars").getElementsByTagName("input")

`for' statement:

P: i
P: inputsInListcarsDiv
P: inputsInListcarsDiv.length
O: i = inputsInListcarsDiv.length

inputsInListcarsDiv.length times (any case):

P: i
O: ToBoolean(i--)
P: inputsInListcarsDiv
P: inputsInListcarsDiv
P: elem
O: elem = inputsInListcarsDiv
P: elem.type
O: elem.type == "checkbox"

inputsInListcarsDiv.length times (worst case):

P: elem
P: elem.checked
P: elem
P: elem.checked
O: !elem.checked
O: elem.checked = !elem.checked

It is still very inefficient by comparison because it involves

- document.getElementById(), i.e. searching the entire document tree for one
element (best case), and returning the reference to the corresponding
element object,

and

- getElementsByTagName(), i.e. searching that element's subtree for
descendant elements of a certain type (), building a live collection
containing the corresponding element objects, and returning that
collection.

The `document.forms' collection, by comparison, is already a live collection
of objects representing `form' elements, and its `elements' collection is
already a live collection representing form controls of that particular
`form' element. Therefore, the first approach requires only the following,
in order of execution:

P: document
P: document.forms
P: document.forms["form1"]
P: document.forms["form1"].elements
P: elemnum
P: document.forms["form1"].elements[elemnum]

[a lot more P's, and O's, and one C]

However, it should be noted that none of those property accesses are
necessary here. One can pass `this' from an event handler attribute of a
control:

function toggleAll(ctrl, name)
{
var checked = ctrl.checked;
var checkboxes = ctrl.form.elements[name];

for (var i = checkboxes.length; i--;)
{
checkboxes.checked = checked;
}
}

<input type="checkbox" … onclick="toggleAll(this, 'foo')">

Which requires the following:

C: toggleAll(this, 'foo')
P: checked
P: ctrl
P: ctrl.checked
O: checked = ctrl.checked
P: ctrl
P: ctrl.form
P: ctrl.form.elements
P: name
P: ctrl.form.elements[name]
O: checkboxes = ctrl.form.elements[name]

`for' statement:

P: i
P: checkboxes
P: checkboxes.length
O: i = checkboxes.length

checkboxes.length times:

P: i
O: ToBoolean(i--)
P: checkboxes
P: i
P: checkboxes
P: checked
O: checkboxes = checked

In any case, one can easily see from this that this kind of element object
access must be more efficient (and cannot be less standards-compliant or
less compatible, see below) than the suggested alternative.

Compatibility
--------------

The suggested alternative is comparably incompatible, because not only it
relies on the availability of the document.getElementById() method, but also
on that element objects have a getElementsByTagName() method.

The document.getElementById(…) method was introduced with W3C DOM (HTML)
Level 1 [1]. But in that Specification, the HTMLElement interface has no
getElementsByTagName() method [2]. It was only introduced there with W3C
DOM Level 2 Core [3].

By contrast, the `forms' and `elements' collections [4,5] date back to the
so-called "DOM Level 0" [6] introduced by Netscape Navigator 3.0 [7,8] and
Internet Explorer 3.0 [9,10]. As a consequence of that, they can be
expected to be supported by any script-enabled HTML user agent.

Unnecessary
------------

Because we already have the `forms' and `elements' live collections in
either proprietary and standards-compliant implementation, it is not
necessary to search the entire document tree for suitable elements.

[x] done.

[x] done.


PointedEars
_________
[1] <http://www.w3.org/TR/REC-DOM-Level-1/level-one-html.html#ID-26809268>
[2] <http://www.w3.org/TR/REC-DOM-Level-1/level-one-html.html#ID-011100101>
[3] <http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-745549614>
[4] <http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-26809268>
[5] <http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-40002357>
[6] <http://www.w3.org/TR/DOM-Level-2-HTML/glossary.html>
[7] <http://devedge-
temp.mozilla.org/library/manuals/2000/javascript/1.3/reference/document.html>
[8] <http://devedge-
temp.mozilla.org/library/manuals/2000/javascript/1.3/reference/form.html>
[9] <http://msdn.microsoft.com/en-us/library/ms531073(VS.85).aspx>
[10] <http://msdn.microsoft.com/en-us/library/ms535249(VS.85).aspx>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top