views:

604

answers:

6

I have a form which posts data to the same page. Based on the user's radio button selection I am inserting checked="checked" into the radio button form element to redisplay the correct selection. This works fine, however when the form is redisplayed (in case of bad input etc), I need a div to be revealed (containing the relevant fields from the form).

I have an onclick event that reveals the div in the first place (before the user has posted the form), and this works fine, but when I redisplay the form I don't want the user to have to manually reveal the form again by clicking.

Therefore I've been trying something along the following lines (heavily cut down for the purposes of this post)...

<link href="styles/style1.css" rel="stylesheet" type="text/css" />
 <script language="JavaScript"> 
  if (document.getElementById('complete_yes').checked) {
   document.getElementById('repair_complete').style.display = 'block';
   } else {
     document.getElementById('repair_complete').style.display = 'none';
  }
 </script>
 <form action="javascript_test.php" method="POST">
  <input id="complete_yes" type="radio" name="complete" checked="checked" value="true"/>Yes
  <input id="complete_no" type="radio" name="complete" value="false"/>No
  <input type="submit" value="Save">
   <div id="repair_complete">
    I'm a div!
   </div>

... but it returns an Object Required javascript error (as it does in the 'real' page):

Message: Object required
Line: 3
Char: 1
Code: 0
URI: http://localhost/repair_system/javascript_test.php

Why is this? Am I not correctly referencing the form element? Apologies if I'm being a "div" (deliberate bad pun intended!), I'm yet to learn about the fun and games of javascript!

A: 

This is because Javascript is executed just before rest of the objects are created.
Place your javascript code into the function body, and add this function into onclick event for whatever you need.

<link href="styles/style1.css" rel="stylesheet" type="text/css" />
<script language="JavaScript"> 
function test() {
  if (document.getElementById('complete_yes').checked) {
   document.getElementById('repair_complete').style.display = 'block';
   } else {
     document.getElementById('repair_complete').style.display = 'none';
  }
}
</script>
<form action="javascript_test.php" method="POST">
<input id="complete_yes" type="radio" name="complete" checked="checked" value="true" onClick="javascript: test();"/>Yes
<input id="complete_no" type="radio" name="complete" value="false" onClick="javascript: test();"/>No
<input type="submit" value="Save">
 <div id="repair_complete">
  I'm a div!
 </div>
</form>
Andrejs Cainikovs
+1  A: 

Your code is being executed as the document is being loaded, and the DOM tree isn't ready yet. So it is trying to access an element that doesn't exist yet.

You probably want to instead write an event handler that toggles the div whenever the checkbox is checked.

I prefer jQuery, which abstracts away things like cross-browser event handling, provides lots of nice helpers and generally makes code look cleaner (when written properly). Something like this should work:

$(document).ready(function() {
    $('#repair_complete').toggle($('#complete_yes').is(':checked'));
}

The above can be roughly translated as:

  • When the document loads, perform the following:
  • Add an event handler for the 'change' event to any elements of type 'input' with a name of 'complete'
  • When the event handler fires, toggle the visibility of the element with ID 'repair_complete' where it should be visible if the element with ID 'complete_yes' is checked

Update: The JS above now actually does what you want, originally I had it written as an onclick

Adam Batkin
+1  A: 

Because your javascript is not wrapped inside a function, the browser is executing it as soon as it "gets to it". In this case, the JS is being executed before the browser has reached the html declaring your form.

The simplest fix therefore is to move the Javascript to after your form. A more robust solution would be to wrap you code in a function, and have that triggered somehow - from what you appear to be trying to do, in this case it'll be the onLoad event of the body tag:

<head>
<script language="JavaScript"> 
  function showHelpDiv() {  
    if (document.getElementById('complete_yes').checked) {
     document.getElementById('repair_complete').style.display = 'block';
    } else {
     document.getElementById('repair_complete').style.display = 'none';
    }
  }
</script>
</head>
<body onload="showHelpDiv()">
 <form action="javascript_test.php" method="POST">
  <input id="complete_yes" type="radio" name="complete" checked="checked" value="true"/>Yes
  <input id="complete_no" type="radio" name="complete" value="false"/>No
  <input type="submit" value="Save">
   <div id="repair_complete">
    I'm a div!
   </div>
iAn
Using onload is a fairly standard approach, but if you have large resources on the page, it can cause a delay between rendering the markup and firing your script. See http://stackoverflow.com/questions/473628/what-external-resources-are-loaded-when-window-onload-event-is-fired-and-what-is for more info on order of load events.
Joel Potter
Thanks for the response - running this code yields the same error though...
chriswattsuk
A: 

It looks to me as though your script is firing before the form is drawn, you may want to move your script block to after the form element. Basically I think that the document.getElementById('complete_yes').checked is looking at null.checked, which would trigger the object required error.

Heat Miser
A: 

You should make the action of the radio button be to change the visibility of the div (that is, "push" the status to it), rather than to "pull" the div status via the radio button status at render time (which as Andrejs said, will be unset).

Ether
A: 

Sounds like the problem is in your initialization code. The javascript is being called before the page is finished rendering. It's one annoying aspect of the "onload" event that in my opinion simply doesn't work as it should in every browser.

There's a cross-browser technique to call initialization code once and only once after the DOM is fully loaded.

Try this code in the HEAD of your HTML:

function showHelpDiv() {  
  if (document.getElementById('complete_yes').checked) {
   document.getElementById('repair_complete').style.display = 'block';
  } else {
   document.getElementById('repair_complete').style.display = 'none';
  }
}

function InitOnce()
{
    if (arguments.callee.done) return;
    arguments.callee.done = true;

    showHelpDiv();
}

/* for Mozilla */
if (document.addEventListener)
{
    document.addEventListener("DOMContentLoaded", InitOnce, null);
}

/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
     document.write("<script defer src=ie_onload.js><"+"/script>");
/*@end @*/

/* for other browsers */
window.onload = InitOnce;

And then you need to create an *ie_onload.js* file that contains this line for IE compatibility:

InitOnce();

I've tried other techniques but none work as perfectly as this. I believe I originally found this solution here: http://dean.edwards.name/weblog/2005/09/busted/

I use it in an online application that receives 500 unique visits a day or so and this has been reliable for us.

Steve Wortham