In a sense, all the previous material in this book has been directed toward this section.
Why? Because the basic problem-solving model for the HTML/JavaScript environment is to use JavaScript functions together with forms in HTML documents.
The function model described in the preceding section would be very simple except for the fact that, in JavaScript, a value passed to a function through a parameter list can be one of three distinctly different things: a value (a character string or number), a form field, or an entire form. These are not interchangeable, and each must be treated differently. In order to explain these differences, consider the simple problem of calculating the area of a circle. Given a radius r:
= π 2 Area r
139 6.3 Using JavaScript Functions with HTML Forms
Recall that prompt() and alert() and document.write() methods provided an I/O interface for these kinds of calculations in Chap. 4. Later in Chap. 4, some JavaScript calculations were initiated as a result of using the onclick event handler in a button field. These approaches were acceptable at the time, but they are too limited to be good solutions for more complex problems. The following detailed analysis of several approaches to implementing this simple calculation in a function may seem tedious and unnecessary because the problem itself is so simple, but a thorough understanding of the analysis is absolutely essential to successful JavaScript programming.
6.3.1
Passing Numerical Values to a Function
A JavaScript function to solve the problem of calculating the area of a circle is:
function getArea(r) {
return Math.PI*r*r;
}
The parameter r is assumed to be a number representing the radius of a circle. The calculation is straightforward, using the PI property of the Math object (Math.PI).
There is no exponential operator in JavaScript (r2 can’t be represented as r^2 as it could in a spreadsheet, for example), so r is just multiplied by itself.
It seems clear that you should be able to pass a value of the radius from a form field to getArea(). However, previous examples in Chap. 4 have provided ample evidence that caution is required! Consider this input element appearing within a form:
<form>
<input type="text" name="radius" maxlength ="6"
size="6" value="-99" />
...
What “value” can be passed from this form to the function? Recall that the name of the field, radius in this case, is not the same as the value associated with this field. In this context, it is important to make sure that a function receiving information through its input parameter list understands how to interpret that input. Consider Document 6.1, which shows one way pass information. Passing radius to getArea will not produce the desired result, nor will radius.value. Why not? Because radius is only the “value”
of the name attribute, and radius.value is still only a character representation of the required numerical input.
You should not be surprised to learn that the calling argument to function getArea() should be parseFloat(radius.value), as shown in Document 6.1.
140 6 JavaScript Functions
6
Document 6.1 (circle1.htm)<html>
<head>
<title>Circle Area (1)</title>
<script language="javascript" type ="text/javascript">
function getArea(r) { return Math.PI*r*r;
</script>}
</head>
<body>
<h1>Circle Area (1)</h1>
<p>
<form>
Enter radius, then press tab key or click on "area"
box.<br />
radius (cm):
<input type="text" name="radius" size="6" maxlength="7"
value="-99",
onblur = "area.value=getArea(parseFloat(radius.value));">
area (cm<sup>2</sup>):
<input type="text" name="area" size="6" maxlength="7"
value="-99">
</form>
</body>
</html>
In Document 6.1, function getArea(r) expects a numerical value equal to the radius of the circle. The name of the function is appropriate to its purpose and is a name unlikely to be associated with a variable name. The shaded line of code uses the onblur event handler to “call” the function when the user clicks elsewhere on the document or presses the Tab key. The value passed to function getArea(r) is parseFloat (radius.value) , which converts the value of the radius field from a string to a num-ber. Note that, in this case, the parseFloat() is not actually required because JavaScript will perform an appropriate type conversion, but it is much better style to perform an explicit type conversion whenever string values need to be interpreted as numbers.
141 6.3 Using JavaScript Functions with HTML Forms
The approach taken in Document 6.1 is called “pass by value.” Another option is to
“pass by name.” The field name is provided as input to the function, which then must do the job of converting the value attribute to a number, as shown in Document 6.2.
Document 6.2 (circle2.htm)
<html>
<head>
<title>Circle Area (2)</title>
<script language="javascript" type ="text/javascript">
function getArea(r) {
var radius=parseFloat(r.value);
return Math.PI*radius*radius;
</script>}
</head>
<body>
<h1>Circle Area (1)</h1>
<p>
<form>
Enter radius, then press tab key or click on "area"
box.<br />
radius (cm):
<input type="text" name="radius" size="6" maxlength="7"
value="-99", onblur = "area.value=getArea(radius);">
area (cm<sup>2</sup>):
<input type="text" name="area" size="6" maxlength="7"
value="-99">
</form>
</body></html>
There is no difference in the results produced by these two approaches, and either is accept-able as long as you are careful not to confuse a field name with its value. If you pass something inappropriate to a function, such as a string value that isn’t converted to a numerical value, then the function will generate a syntax error or return a result of NaN, for “not a number.”
There is another subtlety worth noting about using functions with forms. Consider this modification of Document 6.1:
<script language="javascript" type="text/javascript">
// UNACCEPTABLE CHOICE FOR FUNCTION NAME!
function area(r) { return Math.PI*r*r;
</script>} ...<form>
142 6 JavaScript Functions
6
Enter radius, then press tab key or click on "area"box.<br />
radius (cm):
<input type="text" name="radius" size="6"
maxlength="7" value="-99", onblur =
"area.value=area(parseFloat(radius.value));" />
area (cm<sup>2</sup>):
<input type="text" name="area" size="6"
maxlength="7" value="-99" />
...
In this code, the function name, area, is the same as a field name in the form. Although one could envision a programming environment in which this conflict could be resolved based on the context, this code will simply not work in JavaScript. So,
The names of functions should never be the same as the names of form input fields.
6.3.2
Using Entire Forms as Input
There is yet another way to write a function that calculates the area of a circle. Consider Document 6.3.
Document 6.3 (circle3.htm)
<html>
<head>
<title>Circle Area (4)</title>
<script language="javascript" type ="text/javascript">
function getArea(f) {
var r=parseFloat(f.radius.value);
f.area.value = Math.PI*r*r;
</script>}
</head>
<body>
<h1>Circle Area (3)</h1>
<form>
Enter radius, then press tab key or click on "area"
box.<br />
radius (cm):
143 6.3 Using JavaScript Functions with HTML Forms
<input type="text" name="radius" size="6"
maxlength="7" value="-99", onblur = "getArea(form);" />
area (cm<sup>2</sup>):
<input type="text" name="area" size="6"
maxlength="7" value="-99" />
</form>
</body>
</html>
In this version of function getArea(), the entire form (actually, just information about where the form is located in computer memory) is passed to the function, through the parameter name f. There is no return statement. How, then, is the result of the cal-culation made available to the area form field? The answer lies in these two statements:
var r=parseFloat(f.radius.value);
f.area.value = Math.PI*r*r;
The first statement extracts the numerical value of the radius. The second statement modifies not the form parameter itself, but the value property of one of its fields.
(It automatically converts the number back to text, too.) Note that this approach requires the function to “know” the names of the fields in the form passed as input to the function.
This is a major conceptual difference compared to the previous approaches. The fact that the form and the JavaScript function are linked in this way is not a problem for self- contained documents such as this. The only disadvantage is that it could limit the use of the function in other scripts that use different field names for the same physical quantities.
In the previous discussion of JavaScript’s function model, it was clear that the parameter list acted as a one-way path for input to be passed to a function, but it could not be used to deliver output. Document 6.3 appears to violate this rule because the output has, in fact, been delivered back to the form “through” the parameter f. However, this result does not, in fact, compromise the model. When you pass a “value” to a function, you are actually passing memory addresses telling the function where particular parameters are stored. The function is allowed to make use of information stored at these addresses, but not to change the addresses themselves. Specifically, when the location of a form is passed as a parameter, what the function can do is modify the contents of fields stored in the form. This is what the
f.area.value = Math.PI*r*r;
statement does.
It is important to understand that the name f appearing in the function getArea(form) has nothing to do with names used in the HTML document. This is a consequence of the
“protected” environment created by a function definition, in which names defined within the function are invisible to the rest of a document and script. In fact, it would be accept-able from JavaScript’s point of view to use form as a parameter name, although this might not be a good choice as a matter of style.
144 6 JavaScript Functions
6
The ability of a function to modify fields within a form is important because it is one way to circumvent the restriction that a return statement can return only a single value as output. Suppose you wanted to calculate both the area and circumference of a circle.Does this require two separate functions? No. Consider Document 6.4.
Document 6.4 (circleStuff.htm)
<html>
<head>
<title>Circle Stuff</title>
<script language="javascript" type ="text/javascript">
function circleStuff(f) {
var r=parseFloat(f.radius.value);
f.area.value=Math.PI*r*r;
f.circumference.value=2*Math.PI*r;
</script>}
</head>
<body bgcolor="#99ccff">
<h1>Circle Stuff</h1>
<form>
Enter radius, then press tab key or click on "area"
box.<br />
radius (cm):
<input type="text" name="radius" size="6"
maxlength="7" value="-99", onblur = "circleStuff(form);" />
area (cm<sup>2</sup>):
<input type="text" name="area" size="6"
maxlength="7" value="-99" />
circumference(cm):
<input type="text" name="circumference" size="6"
maxlength="7" value="-99" />
</form>
</body>
</html>
145 6.3 Using JavaScript Functions with HTML Forms
Document 6.4 includes an additional form field for the circumference, calculated in the
f.circumference.value=2*Math.PI*radius;
statement in circleStuff(). Both the area and the circumference are calculated within the function, but no return statement is used.
It is not quite true that a function accepting a form name as a parameter must know the values of all the <input... /> tag name attributes. Recall from Chap. 5 that all form fields are available in an array called elements[] which is automatically created along with a form. The following modification of the function in Document 6.4 will also work.
It uses the elements[] array to access the form fields.
function circleStuff(f) {
var r=parseFloat(f.elements[0].value);
f.elements[1].value=Math.PI*r*r;
f.elements[2].value=2*Math.PI*r;
}
In this case, the function must still be aware of the physical meaning of each form field as well as its position among the other fields.
It is important to understand that the significance of Document 6.5 rests on its demonstration of how to use a single function to generate more than one output value, to circumvent the requirement that a function can return only a single value.
6.3.3
Using Arrays to Return Output Values
Yet another way to return multiple values from a function is to have the function return an array, the elements of which contain the output values of interest. Document 6.5 shows how to do this by presenting another version of the “circle stuff” code given in Document 6.4.
Document 6.5 (circleStuff2.htm)
<html>
<head>
<title>Circle Stuff with Arrays</title>
<script language="javascript" type ="text/javascript">
function circleStuff(r) { var A = Array();
A[0] = Math.PI*r*r;
A[1] = 2*Math.PI*r;
return A;
</script>}
</head>
146 6 JavaScript Functions
6
<body bgcolor="#99ccff"><h1>Circle Stuff</h1>
<form>
Enter radius, then press tab key or click on "area" or
"circumference" field.<br />
radius (cm):
<input type="text" name="radius" size="6"
maxlength="7" value="-99", onblur = "var A = Array();
A = circleStuff(parseFloat(radius.value));
area.value = A[0]; circumference.value = A[1]; " />
area (cm<sup>2</sup>):
<input type="text" name="area" size="6"
maxlength="7" value="-99" />
circumference(cm):
<input type="text" name="circumference" size="6"
maxlength="7" value="-99" />
</form>
</body>
</html>
Of course, with this approach it is necessary for the programmer to keep track of which output value is stored in which array element.