In Part 1, I'll walk you through a solved problem for defining a JavaScript function computeSalesTax()
that could be used on a shopping web site.
There is nothing you have to turn in from Part 1. However, Part 1 forms the basis of everything you do in the remainder of this lab, so you need to work through it carefully.
In Part 2 , I'll walk you through a second solved problem—namely, computing the percentage margin of victory between two candidates—but this time, step 3, the function body, is left for you to figure out yourself.
The five steps consist of the four step "design recipe" we talked about previously in class—and described in detail on the Wiki Page CISC103_Design_Recipes—plus one extra step—using your function in one or more useful working web pages:
Here's some more detail about what we'll do:
computeSalesTax()
function using the first three steps of the design recipe. computeSalesTax()
function in a file on the computercopland.udel.edu
copland.udel.edu
./www/htdocs/CIS/103/pconrad/bin/js
to get to the js> prompttestComputeSalesTax()
function—this is a separate function that automates the testing so that we don't have to retype all the tests each time we make a change to the function. We can store this function in the same file computeSalesTax.js
, along with the function definition for testComputeSalesTax()
. testComputeSalesTax.html
computeSalesTax()
function to build a couple of useful working web pages
computeTax.html
will ask the user for the price of an item, and the sales tax rate, and compute the sales tax and grand total.selectTax.html
will do the same thing, but will allow the user to select the sales tax rate using a radio button. computeSalesTax.js
, thus illustrating how a single JavaScript file can be used for multiple web pages. To get ready for this lab, you need to copy some files into a new directory under your web page http://copland.udel.edu/~youruserid/cisc103/lab10
There are two possible ways to do this.
Here's all three commands the way you would type them in. Note that copland.udel.edu%
is just the Unix prompt—you don't type that part in.
copland.udel.edu% mkdir ~/public_html/cisc103/lab10
copland.udel.edu% cp /www/htdocs/CIS/103/pconrad/06F/labs/lab10/* ~/public_html/cisc103/lab10 copland.udel.edu% chmod -R 755 ~/public_html/cisc103/lab10
copland.udel.edu%
The second way is to go to the web page http://www.udel.edu/CIS/103/pconrad/06F/labs/lab10, select each file individually, do a save as on each individual file to a folder on your hard disk.
Then, use SSH Secure File transfer to:
Hopefully, this illustrates why a little knowledge of Unix commands is very handy when working with web sites!
computeSalesTax()
In this step, we define what the function computeSalesTax consumes, and what it produces. We write the following inside the file computeSalesTax.js.
We can do this using Notepad on the PC, just as we did when creating HTML files.
// computeSalesTax.js // P. Conrad for CISC103 sect 99, Fall 2006, lab10, 11/16/2006 // function computeSalesTax.js // computes sales tax // consumes: // a dollar amount (number) // a sales tax rate (a number, expressed as a percentage, e.g 5.5) // produces: // the sales tax amount, rounded to the nearest penny
In this stage, we may also add the function header, and a stub for the body.
A stub is a version of the body that
For example, in this case, since the function produces a number, we can just use return 0;
as the stub.
return
is used to signal to JavaScript that we are ready to produce the answer. return
is the answer that is produced.return 0;
means that we producing 0
as the answer. 0
isn't the correct answer, but it can stand in for the correct answer until we've completed steps 2 and 3.So here, is the complete contract, including the function header, and a stub for the body:
// computeSalesTax.js // P. Conrad for CISC103 sect 99, Fall 2006, lab10, 11/16/2006
// function computeSalesTax: computes sales tax // consumes: // dollars: a dollar amount (number) // taxRate: a sales tax rate (a number, expressed as a percentage, e.g 5.5) // produces: // the sales tax amount, rounded to the nearest penny, expressed as a string function computeSalesTax(dollars,taxRate) { return 0; // stub! replace this with a correct body later }
In this step, we come up with examples. For each example, we specify
dollars
and taxRate
For example, if the price of an item is $10, and the tax rate is 5%, the function should return 0.50
We can write this in the form of an imaginary conversation between the user and the JavaScript interpreter. We try several differ net values, to see if we get what we expect.
typeof
) shows us whether the value is being returned as a string or as a number. (We need to to be a string so that the last zero digit doesn't get cut off.) js> computeSalesTax(10,5) 0.50 js> computeSalesTax(10,5.5) 0.55 js> computeSalesTax(1,5.5)
0.06 js> typeof computeSalesTax(1,5.5) string js>
We then turn this into a comment that we put in our JavaScript file:
// Examples: // js> computeSalesTax(10,5); // 0.50 // js> computeSalesTax(10,5.5); // 0.55 // js> computeSalesTax(1,5.5); // 0.06 // js> typeof computeSalesTax(1,5.5) // string // js>
We are now ready to complete the body of the function.
In developing the body, the question we ask ourselves is
In this case, we see that we first need to convert the percent (e.g. 5) into a decimal such as 0.05. We do this by dividing by 100. We use the word var
to indicate that the new variable we are defining—namely taxRateAsDecimal
—is a local variable, one known only inside the function body.
var taxRateAsDecimal = taxRate / 100;
We then multiply the taxRate by the dollars passed in, to find the total tax:
var dollarAmount = dollars * taxRateAsDecimal;
Next, we have to find some way to round off the answer to only two digits.
We could use the toFixed()
method—this is a method that can be applied to any object of type number. For example, at the JavaScript prompt, try the following. The argument to toFixed()
is the number of decimal places you want in your final answer, which for dollar amounts is always 2
:
js> (12).toFixed(2);
12.00
js> (12.5).toFixed(2);
12.50
js> (12.501).toFixed(2);
12.50
js> (12.509).toFixed(2);
12.51
js>
Unfortunately, there is a problem with toFixed()—it rounds inconsistently—sometimes up, and sometimes down. (This is a bug in the JavaScript interpreter):
js> (0.045).toFixed(2)
0.04
js> (0.145).toFixed(2)
0.14
js> (0.245).toFixed(2)
0.24
js> (0.545).toFixed(2)
0.55
js> (0.845).toFixed(2)
0.84
js>
So, an alternative is to use a trick. We first round the number using a method described on this web page:
http://www.javascriptkit.com/javatutors/round.shtml
js> function roundToTwoPlaces(num) {
return Math.round(num * 100) / 100;
}
js> roundToTwoPlaces(0.545)
0.55
js> roundToTwoPlaces(0.045)
0.05
js> roundToTwoPlaces(0.145)
0.14
js> roundToTwoPlaces(0.845)
0.85
js>
Once the number is rounded to two places, we can use the toFixed(2) method to get it to show both places (instead of cutting of 3.50 to 3.5, for example). Note that additional methods—such as toFixed(2)—can be applied directly to the result of another function call (as in roundToTwoPlaces(0.502).toFixed(2)
).
js> roundToTwoPlaces(0.502)
0.5
js> roundToTwoPlaces(0.502).toFixed(2)
0.50
js>
So, the final version of this body looks like this. Note that we need an additional function to get the job done. We can list that function immediately after the definition of computeSalesTax.
Note that we have a contract and examples for that function also. If we have to write a helper function, we need to go through the same design recipe, including all the steps. To really complete the job, we'll need to test that function also when we get to step 4.
function computeSalesTax(dollars,taxRate) { // convert from percent to decimal, e.g. from 5% to 0.05 var taxRateAsDecimal = taxRate / 100; // multiply to get the dollar amount var dollarAmount = dollars * taxRateAsDecimal; // round to two decimals, and return as a string return } // function roundToTwoPlaces // rounds a number to two places // consumes: num ( a number) // produces: the same number rounded to two decimal places // // Examples: // js> roundToTwoPlaces(5.505) // 5.51 // js> roundToTwoPlaces(5.499) // 5.0 // js> // function roundToTwoPlaces(num) {
return Math.round(num * 100) / 100;
}
To test, we first use the command line JavaScript interpreter
copland.udel.edu
./www/htdocs/CIS/103/pconrad/bin/js
to get to the js>
prompt.copland.udel.edu% cd ~/public_html/cisc103/lab10 copland.udel.edu% /www/htdocs/CIS/103/pconrad/bin/js js>
This involves typing each one of your example test cases in, one at a time, and comparing the result with what you hoped to get. You first load the function into the JavaScript interpreter with the command:
js> load("computeSalesTax.js"); js>
Then, you type in the examples that you want to test, one at a time. This can be somewhat tedious, but it works.
Here's how that whole session looks:
copland.udel.edu% cd ~/public_html/cisc103/lab10 copland.udel.edu% /www/htdocs/CIS/103/pconrad/bin/js js> load("computeSalesTax.js"); js> computeSalesTax(10,5) 0.50 js> computeSalesTax(10,5.5) 0.55 js> computeSalesTax(1,5.5) 0.06 js> typeof computeSalesTax(1,5.5) string js>
A more efficient way to test is to use an automated script with a testComputeSalesTax()
function—this is a separate function that automates the testing so that we don't have to retype all the tests each time we make a change to the function. We can store this function in the same file computeSalesTax.js
, along with the function definition for testComputeSalesTax()
.
The function looks like this:
function testComputeSalesTax() { if (computeSalesTax(10,5) =="0.50") print("test 1: passed"); else print("test 1: failed"); if (computeSalesTax(10,5.5) =="0.55") print("test 2: passed"); else print("test 2: failed"); if (computeSalesTax(1,5.5) =="0.06") print("test 3: passed"); else print("test 3: failed"); if (typeof(computeSalesTax(1,5.5)) =="string") print("test 3: passed"); else print("test 3: failed"); }
Running it looks like this:
copland.udel.edu% /www/htdocs/CIS/103/pconrad/bin/js js> load("computeSalesTax.js"); js> testComputeSalesTax() test 1: passed test 2: passed test 3: passed test 3: passed js>
Finally, we'll use the computeSalesTax()
function to build a useful working web page, one that asks the user for the price of an item, and the sales tax rate, and compute the sales tax.
Take a look at the page computeTax.html. Look both at the page itself, and the source code.
Consider, especially, this part:
<script src="computeSalesTax.js" type="text/javascript"></script>
<script type="text/javascript">
function whatToDoWhenYouPressTheButton()
{
// get the values out of the form
var dollarAmt = parseFloat(window.document.getElementById("dollarAmtInputField").value);
var taxRateAsPercentage = parseFloat(window.document.getElementById("salesTaxInputField").value);
// compute the result
var result = computeSalesTax(dollarAmt,taxRateAsPercentage);
// stick the result back into the web page (using DHTML)
window.document.getElementById("whereTheSalesTaxGoes").innerHTML=result;
}
</script>
The first <script>
element pulls in the computeSalesTax.js file that we developed in steps 1-4. The second script element defines a JavaScript function whatToDoWhenYouPressTheButton()
that is used as the Event Handler for the button:
<tr>
<td colspan="2" class="centerIt">
<input type = "button" value = "Calculate" onclick = "whatToDoWhenYouPressTheButton()" />
</td>
</tr>
If you don't understand how this works, ask questions of your TA and your instructor.
selectTax.html
that will do the same thing, but will allow the user to select the sales tax rate using a radio button or a drop down menu (selecting tax rates from among those for several nearby locations—including Delaware, were the sales tax is zero!) typeof
will finally start paying off.) computeSalesTax.js
, thus illustrating how a single JavaScript file can be used for multiple web pages.
What do we mean by "Margin of Victory"
In this part, we'll develop a web page that computes the "percentage margin of victory" between two candidates in an election. This is useful, for example, in determining whether an automatic recount is needed, and also in distinguishing between a very close election, and one that isn't very close.
For example, suppose you win an election by 100 votes.
In the former case, your margin of victory is 100 votes out of 200 votes cast, or a margin of 50% (you got 75% of the vote, and your opponent got 25%, a difference of 50%).
In the latter case, you received just under 50.7% of the vote, and your opponent received just over 49.3% of the vote. Hence the margin of victory is only a little less than 1.4% of the vote, which might be enough to trigger an automatic recount in some states.
If you do a web search on "margin of victory" and "automatic recount", you'll find many examples of this in American electoral politics, since many states do have laws requiring an automatic recount when the margin of victory is small.
To keep our problem simple, we will only consider elections between exactly two candidates, and ignore third party or write in candidates. (In a future semester, I'll expand the problem to add third party and write in candidates, in the interest of expanding democracy and making the problem more challenging.)
In this lab, you "fill in the blanks" for step 3, "developing the body of the function. I've developed the contract, and examples, as well as a test script and an application of the function.
What to do:
~/public_html/cisc103/lab10
).return 0;
with some JavaScript code that computes the correct answer.
{ // @@@ fill in body here! return 0; // @@@ this is just a place holder---remove this line! }You'll replace
// fill in body here!
with JavaScript code to compute the margin of victory.
copland.udel.edu
and bring up a Unix prompt. Change directory into your lab10 directory, and then bring up the JavaScript prompt, as shown:copland.udel.edu% cd ~/public_html/cisc103/lab10 copland.udel.edu% /www/htdocs/CIS/103/pconrad/bin/js js>
computeMarginOfVictory.js
to a file on your PC, and open it with notepad or wordpad (whichever seems to work). Open it up and start editing it to add the body you think you need.js> load("computeMarginOfVictory.js") js> computeMarginOfVictory(550,450); 10 js>
testComputeMarginOfVictory()
function as shown here:
js> testComputeMarginOfVictory()
test 1: passed
test 2: passed
test 3: passed
test 4: passed
js>
marginOfVictory.html
web page (the one on your copland.udel.edu web site), and see if it computes correct results. (If you've copied the files correctly and if your computeMarginOfVictory()
function passes all the tests, then it should.)Before submitting on WebCT, be sure that your marginOfVictory.html
web page works correctly.
You only need to upload your computeMarginOfVictory.js
file to WebCT. Upload and submit that, and you are finished. That is the only file you need to submit.
Due 11:55pm Thursday November 30
Penalties for late submissions:
if submitted by 11:55pm on: | days late | penalty |
Fri Dec 1 | 1 | none |
Sat Dec 2 | 2 | 4% |
Sun Dec 3 | 3 | 8% |
Mon Dec 4 | 4 | 8% |
Tue Dec 5 | 5 | 16% |
Wed Dec 6 | 6 | 32% |
Thu Dec 7 | 7 | no credit (zero) |