Thứ Năm, 14 tháng 10, 2010

Dynamic Form submit value (JAVASCRIPT)

<form name="Submit" action="" method="post" enctype="multipart/form-data" id="form1">
</form>
<script>
function changeAction(val) {
document.getElementById("form1").setAttribute("action", val);
}
</script>
<a href="#" onclick="changeAction('test1.asp');">
<a href="#" onclick="changeAction('test2.asp');">
<a href="#" onclick="changeAction('test3.asp');">


Apple Developer Connection

ADC Home > Internet Technologies > Web Content >

Dynamic Forms with DHTML

Forms are key components of all Web-based applications. But important as they are, Web developers often present users with forms that are difficult to use. There are three common problems:

  • Forms can be too long. A seemingly endless list of questions is sure to make the user click the back button or jump to another site.
  • In many situations a specific user will need to fill out only some of the form elements. If you present needless questions to a user, you’ll add clutter to your page and encourage the user to go elsewhere.
  • Form entries often need to conform to certain formats and instructions. Adding this information to a Web page can make for a cluttered and unappealing screen.

Here’s an example of a form that’s sure to drive even the most intrepid user away. This article will show you how a little JavaScript can address each of these problems and make life a bit easier for the users of your site.

Choosing The Form You Want

A long form can be shortened in a number of ways. The Internal Revenue Service, for example, provides simple and complex versions of many of its forms; the 1040-A income tax form has a simpler version, the 1040-EZ, for people whose tax lives are less complicated.

If you have multiple versions of a form, the chief task becomes pointing people to the right form. Often, a simple set of links will do: “click here for the simple form, click here for the more complicated one.” Alternatively, a single page can show one of several forms that the visitor can choose between using radio buttons. This approach is especially nice for complicated pages and for users working over slow connections, since there’s no delay as a new page loads. Take a look at this example of a frame-like approach to providing multiple forms.

This approach uses Dynamic HTML (DHTML), which has several benefits over using IFRAMES to do the same thing. First, DHTML allows for more flexible formatting than IFRAMEs permit. You can apply background images, borders, fonts, and all the other features you’ve learned to expect from HTML and Cascading Style Sheets to DHTML objects. In contrast, IFRAMES have almost no configurable features. Second, if someone fills out one form, switches to another, then switches back, there’s a good chance that the browser will lose the information that was initially entered. This problem doesn’t exist in the DHTML solution. Third, with DHTML you can do tricky things like clipping and moving the form around the page. You could do these things by combining IFRAMES and DHTML, but you might as well just use DHTML in the first place.

The implementation in the choose_form.html page is pretty straightforward, especially if you’ve read the Internet Developer article Hide/Show Layer. Each form is placed in a DIV, and each DIV is associated with a radio button. When you select a radio button, you change the visibility of the associated DIV. View the source of the example to see the code. Here’s a brief breakdown.

First, each form lives in its own DIV. Here’s a somewhat simplified version of the DIV that holds the form:

<div id="ez" 
style="position:absolute;top:100px;left:5px;visibility:hidden;">
<form name="ez_form" method="POST"
action="http://mydomain.com/cgi-bin/thanks.cgi">
<table>
<tr><td>Name:</td><td><input type="text"></td><tr>
<tr><td>Income:</td><td><input type="text"></td></tr>
</table>
<input type="submit">
</form>
</div>

There are a few things to note here. First, the DIV has an id (id=”ez”), which is used to identify which DIV we want to hide or show. Next, the DIV has stylesheet information. This positions the DIV (position:absolute;top:100px;left:5px) and hides it (visibility:hidden) when the page is first loaded.

The trick is to use the radio buttons to show the appropriate DIV. Here’s one of the radio buttons:

<input type="radio" name="form_type" value="ez"
onClick="switchDiv('ez');">Easy Form

Clicking on this button calls the switchDiv() function, which first checks to see if the browser can handle DHTML. If it can, two functions are called: hideAll(), which hides all the DIVs which contain forms, and thenchangeObjectVisibility(), which shows the requested DIV.

Here’s the switchDiv() function:

function switchDiv(div_id)
{
var style_sheet = getStyleObject(div_id);
if (style_sheet)
{
hideAll();
changeObjectVisibility(div_id, "visible");
}
else
{
alert("sorry, this only works in browsers that do Dynamic HTML");
}
}

First, switchDiv() tries to get the stylesheet of the DIV with the id of div_id. It uses a function calledgetStyleObject() which has been described in the article on hiding and showing layers. The getStyleObject() function takes the id of a DIV and returns the DIV’s style sheet. The function takes care of the cross-browser issues surrounding stylesheet access, so this script will work on Netscape 4.0+ and Internet Explorer 4.0+. If a visitor is using an earlier browser, the getStyleObject() function returns false. Here’s the function for your perusal:

function getStyleObject(objectId) {
// checkW3C DOM, then MSIE 4, then NN 4.
//
if(document.getElementById && document.getElementById(objectId)) {
return document.getElementById(objectId).style;
}
else if (document.all && document.all(objectId)) {
return document.all(objectId).style;
}
else if (document.layers && document.layers[objectId]) {
return document.layers[objectId];
} else {
return false;
}
}

Getting back to the switchDiv() function; if getStyleObject() successfully returns a stylesheet, the hideAll() andchangeObjectVisibility() functions are called.

The changeObjectVisibility() function was also described in the article on hiding and showing layers. It takes two parameters, the id of the DIV that should be changed, and the new visibility setting for that DIV (visible orhidden):

function changeObjectVisibility(objectId, newVisibility) {
// first get the object's stylesheet
var styleObject = getStyleObject(objectId);

// then if we find a stylesheet, set its visibility
// as requested
//
if (styleObject) {
styleObject.visibility = newVisibility;
return true;
} else {
return false;
}
}

First, the function gets access to the DIV’s stylesheet using getStyleObject(). If the stylesheet exists, the visibility of the DIV is changed according to the contents of the second parameter. If the second parameter is hidden, the DIV becomes hidden. If the parameter is visible, the DIV becomes visible.

The last function of note in the script is hideAll():

function hideAll()
{
changeObjectVisibility("ez","hidden");
changeObjectVisibility("full","hidden");
changeObjectVisibility("superduper","hidden");
}

This function simply calls changeObjectVisibility() three times, once to hide each DIV containing a form.

Putting this all together, clicking on a radio button calls switchDiv() which hides all the DIVs, using hideAll(), and then shows the appropriate DIV using changeObjectVisibility(). Clicking on another radio button then hides all the DIVs again and shows the DIV you want.

The functions getStyleObject(), and changeObjectVisibility() will be used in a couple of other examples in this article. Because they’ll be used so frequently, it’s a good idea to move them into a file which later scripts will include, like this:

<script src="utility.txt"></script>

It’s generally a good idea to put functions that are used in many scripts in a separate document. That way, if you want to change one of the functions, you only have to change one document, rather than going into every script that uses the function and changing it there.

Forming Wizards


You’ve just seen that presenting shorter forms can make life easier for people who don’t need to answer every question. But what about the people who do have to answer every item in a long list of questions? You can make their lives more pleasant as well.

One way to make a long list of questions more palatable is to break the form into several pages, like the wizards that are common in software applications. This limits the number of questions your visitors see at any given time, reducing the chance that they’ll run in fear. Also, once someone’s gone through a page or two of questions, they’re more likely to fill the whole thing out.

Many sites break long forms into small pieces submit each portion to a CGI script running on the web server. Most e-commerce sites break the ordering form into at least three forms: one for verifying the purchase, one for collecting shipping information, and one for billing information. When the first form is submitted, the information is sent to the web server and a program on that server saves the information and presents the second form.

This method has the advantage of saving information incrementally. If, for instance, you’re doing a survey, it means that even if a visitor stops filling out the survey half-way through, you still have some information. The down side of this method is that each part of the form needs its own trip to the server and back. If the connection is slow, that might mean losing your visitor due to lag time. This method also assumes that you have access to a scripting engine on the web server and that you know how to write server-side scripts.

Another, less frequently used solution, is to present the different parts of the form using DHTML. Put each of the sub-forms in its own DIV. Start off showing the sub-form in the first DIV, and then, when the visitor finishes filling out that portion, use JavaScript to hide the first DIV and show the second one. This breaks the form up into smaller chunks, saves the time taken up by multiple trips to the server, and doesn’t require access to server-side scripts. Take a look at the DHTML wizard to see an example of this in action. Then look at the source of the wizardto see what’s involved.

The Workings of the Wizard


There are a few interesting aspects to the wizard code. First, let’s look at a slightly shortened version of the second DIV:

<div id="part2" style="position:absolute;top:150px;left:50px;visibility:hidden;">
<form name="pet_info">
<table>
<tr><td>Your pet's name:</td>
<td><input name="petname" type="text"></td></tr>

</table>

<input type="button" value="prev"
onClick="switchDiv('part2', 'part1');">

<input type="button" value="next"
onClick="switchIfDone(this.form, 'part2', 'part3');">
</form>
</div>

There are a few things to note here. As before, the DIV has an id, which allows JavaScript to hide and show the DIV on command. The DIV also has stylesheet information which positions the DIV and hides it when the page is first loaded.

Inside the DIV sits a form with a series of questions. Note that the form has a name, as does each question. The script will be using these later to collect the data from the various sub-parts of the form.

In addition to the questions, there are two buttons at the end of the form. The first button allows the visitor to go back a page if she wants to change an answer. It calls the switchDiv() function and passes it two parameters: theid of the DIV that holds the part of the form the visitor is currently viewing and the id of DIV containing the part that should be visited next. The second button allows the visitor to move to the next part of the form once the part currently viewed has been completely filled out. It calls the switchIfDone() function which takes three parameters: the name attribute of the form, the id of currently visible DIV, and the id of the DIV that should be shown next.

The two functions which do most of the work are switchDiv() and switchIfDone(). The first of these is pretty straightforward:

function switchDiv(this_div, next_div)
{
if (getStyleObject(this_div) && getStyleObject(next_div)) {
changeObjectVisibility(this_div, "hidden");
changeObjectVisibility(next_div, "visible");
}
}

This function is similar to the changeDiv() function seen in the previous example. It uses the getStyleObject()function to make sure that the browser can handle DHTML. If so, it calls the changeObjectVisibility() function to hide the DIV that’s currently visible and show the DIV that should be seen next.

The switchIfDone() function determines whether or not the form has been completely filled out. If the form has been completed and the user is viewing the final portion of the form, all the information from all of the forms should be sent to the server. If the user is not viewing the final portion of the wizard, then the switchDiv() function will move to the next portion of the form.

The switchIfDone() function is called when a visitor hits the next button on the form, like so:

<input type="button" value="next" 
onClick="switchIfDone(this.form, 'part2', 'part3');">

The first parameter is a pointer to the form which contains the button. The function will check to see if this form has been properly filled out. If it has, the function will hide part2 and show part3.

Here’s the code to figure out if the form has been completed:

  var complete = true;
for (var loop=0; loop < the_form.elements.length; loop++)
{
if (the_form.elements[loop].value == "")
{
complete = false;
}
}

This loops through all the elements of the form and makes sure none of them are blanks. If a blank is found, the variable complete gets set to false.

Once the loop has executed, this code runs:

  if ((complete == true) && (next_div == "finished")) 
{
submitTheInfo();
}

This calls submitTheInfo() if the form is completely filled out, and the next_div parameter has been set to finished. In order for this to work correctly, the next button in the DIV containing the last part of the wizard should look like this:

<input type="button" value="next" 
onClick="switchIfDone(this.form, 'part3', 'finished');">

If ‘finished’ is not the third parameter, this else-if portion will execute.

else if (complete == true) 
{
switchDiv(this_div, next_div);
}

If the form is complete, switchDiv() is called, showing the visitor the next part of the wizard. If this else-if fails, the form must not have been completed, and the final else runs:

else {
alert('please complete the form before moving on');
}

The last function in the script is the one that actually submits the information to the CGI script, or does whatever else you want to do with the information your visitor has provided:

function submitTheInfo()
{
var submission_string="";
for (var form_loop=0; form_loop<document.forms.length; form_loop++)
{
for (var elems=0; elems<document.forms[form_loop].length;elems++)
{
if (document.forms[form_loop].elements[elems].name != "")
{
submission_string += document.forms[form_loop].name + "_" +
document.forms[form_loop].elements[elems].name + "=" +
document.forms[form_loop].elements[elems].value + "\n";
}
}
}
document.hiddenform.the_text.value = submission_string;

// the next two lines are written for debugging -
// to put the script into action
// comment out the changeObjectVisibility() line
// and uncomment the document.hidden.form.submit() line
//

// document.hiddenform.submit();
changeObjectVisibility("hiddenstuff","visible");

document.hiddenform.submit();
}

This function loops through all the forms on the page and all the elements of each form, constructing a string containing all the information that has been provided. It then sticks this string in a textarea in a hidden form, and then submits the form. The DIV containing the hidden form looks like this:

&div id="hiddenstuff" style="position:absolute;top:300;left:5;visibility:hidden;">
<form name="hiddenform" method="POST" action="my_cgi_script">
<textarea name = "the_text" cols=40 rows=20>
</textarea>
</form>
</div>

Notice that the form has a method and an action. This tells the browser which script should be run when the form is submitted. The line

  document.hiddenform.the_text.value = submission_string;

sticks the string holding the values of the form into the textarea, and the line:

  document.hiddenform.submit();

submits the form to the CGI script listed in the action attribute of the form.

Just like the previous example, the heart of the wizard involves hiding and showing DIVs based on the actions of the visitor. The wizard is slightly more complicated because it must collect information from several forms before submitting the information to the CGI script, but other than that it’s the same idea.

Too Much Information


Sometimes the answer to one question can make an entire set of sub-questions irrelevant. If someone filling out your apartment rental form says he or she doesn’t have a pet, you shouldn’t ask for pet-specific information. You could have two forms, one for pet owners, and another for the petless folks, but that means you have to maintain multiple forms which are all pretty similar to each other. Another solution is to use DHTML to make a set of questions appear or vanish based on the answer to another question. Take a look at the rental form for an example of how this might look.

This script works by modifying the display property of a stylesheet. If the display property of a stylesheet is set tonone, the DIV containing that stylesheet doesn’t take up any space on the screen (and is therefore invisible). If thedisplay property is set to block, the DIV will appear on the page. When the display property changes from none toblock, all the elements below the DIV will shift down to make room for the DIV’s contents. When the display property goes from block to none, the DIV will vanish and everything below it will shift up. Notice that this is quite different than the visibility property. When you make a hidden DIV visible, you won’t affect the positioning of anything else on the screen. And if the DIV is positioned over other elements of the page, it will appear on top of them.

Take a look at the source of the rental form to see what’s going on. The JavaScript is triggered when a visitor clicks on one of the radio buttons saying he or she has a pet. Each of those buttons looks something like this:

<input type="radio" name="pet" 
onClick="hideAll(); changeDiv('cat_questions','block');">cat

If the visitor owns a cat, the function hideAll() is called to hide any pet-specific questions that might be showing, and then calls changeDiv() with cat_questions and block as parameters. A bit lower on the page I have a DIV with an id of cat_questions. Here’s an abbreviated version of the DIV:

<div id="cat_questions" style="margin-left:30px;display:none">
Does your cat have fleas?
<input type="radio" name="fleas" value="yes">yes
<input type="radio" name="fleas" value="no">no
</div>

Notice the display:none property in the stylesheet. This tells the browser not to display the contents of this DIV. The changeDiv() function is similar to changeObjectVisibility():

function changeDiv(the_div,the_change)
{
var the_style = getStyleObject(the_div);
if (the_style != false)
{
the_style.display = the_change;
}
}

First getStyleObject() is called to get the stylesheet of the DIV we want to appear. If the stylesheet exists, itsdisplay property is changed, causing the DIV to appear on the page if the_change is block, or removing it ifthe_change is none. The getStyleObject() function used here is slightly different from the one we’ve been using. Unfortunately, the display property cannot be changed with JavaScript in Netscape 4, so this version ofgetStyleObject() returns false if the person is using Netscape 4.

The hideAll() function calls changeDiv() on each of the DIVs containing pet-specific questions.

function hideAll()
{
changeDiv("cat_questions","none");
changeDiv("dog_questions","none");
changeDiv("bird_questions","none");
}

And that’s it — another variation on the theme of using JavaScript to change stylesheet properties of DIVs containing form elements. The main difference between this example and the previous ones is that this example tweaks the stylesheet’s display property, rather than its visibility property.

Good Form


You can also make forms easier to fill out by helping people enter their information in the correct format. Often forms are cluttered with instructions about how to format dates, how to enter credit card numbers, etc. Theformatting assistant page shows how you can help your users without cluttering the form up with instructions.

There are a few things happening in this example. First, clicking on a text box causes a formatting widget to pop up, indicating how an element should be filled out. As you can probably guess, this is done by sticking the widget inside a DIV and changing the DIV’s visibility. In addition, the script prevents the visitors from typing directly into the text fields — they have to use the widget. This ensures that the formating will be correct. Finally, the script takes the information out of the widget and sticks it in the text field.

Let’s first look at one of the main text boxes, the one where a visitor tries to enter a name:

Name: <input type="text"  name="the_name" 
onFocus= "hideAll();
showAndFocus('nameDiv',document.name_form.first_name);"><br>

This input field has an onFocus event handler. When someone clicks into the text box, that triggers a focus event, and runs the JavaScript attached to that event. In this case the hideAll() function is called, hiding whatever widgets are visible, and then the showAndFocus() function is called to show the appropriate widget.

The hideAll() function should look familiar:

function hideAll()
{
changeObjectVisibility("dateDiv","hidden");
changeObjectVisibility("nameDiv","hidden");
}

It calls the changeObjectVisibility() function that we’ve used in the other examples to set the visibility of the indicated DIVs to hidden.

The showAndFocus() function shows the correct widget and moves the cursor from where the user clicked to a form element in the widget. It takes the two parameters: the id of a DIV and a form field to which the cursor should be moved to. For this example, it’s passed the DIV id nameDiv which is the DIV containing the name widget. The second parameter, document.name_form.first_name, is the text field in the widget where the cursor will be focused. Here’s the showAndFocus() function:

function showAndFocus(div_id, field_to_focus)
{
var the_div = getStyleObject(div_id);
if (the_div != false)
{
changeObjectVisibility(div_id, "visible");
field_to_focus.focus();
}
}

First, the function makes sure it can access the stylesheet of the DIV, using our old friend getStyleObject(). If it can get the stylesheet, it calls another old friend changeObjectVisibility() to make that DIV visible. Then it calls thefocus() method of the form element so that the cursor moves into the widget. Any time someone clicks on the main name field, the widget pops up and grabs the cursor. That’s how we can be sure that whatever’s in the main name field is correctly formatted. The only way to get anything in there is via the name widget.

The name widget looks like this:

<div id="nameDiv" style="position:absolute;top:50px;left:100px;
visibility:hidden;z-index:2;background-color:#CCCCCC">
<form name="name_form">
First name: <input type="text" name="first_name"><br>
Last Name: <input type="text" name="last_name"><br>
<input type="button" value="DONE"
onClick="fillInName(this.form.first_name.value,
this.form.last_name.value);">
</form>
</div>

It’s a DIV with a form inside it, similar to what I used earlier. The last form element is the DONE button, which callsfillInName() when it’s clicked. The fillInName() function takes the information that’s been entered into the widget, sticks it in the main name field, and then hides the widget:

function fillInName(first_name, last_name)
{
document.main_form.the_name.value =
first_name + " " + last_name;

changeDiv("nameDiv","hidden");
}

The widget for the date information works similarly. Take a look at the form assistant source code to see the whole script.

Conclusion


In this article I demonstrated four different ways to use DHTML to make forms easier to fill out. Letting people choose which form they need ensures that the forms people see are no more complicated than they need to be.

The interesting thing about all these applications is that even though they look different, the implementations are very similar. In fact, several functions were reused in all the examples. Good functions are like legos, you can use the good ones in lots of different applications. Take the functions you’ve seen here and try to reuse them in your own applications. You’ll be sure to formulate something formidable in no time.



Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2010 Apple Inc.
All rights reserved. | Terms of use | Privacy Notice

Không có nhận xét nào: