reptile7's JavaScript blog
Thursday, November 26, 2015
 
Adventures in Amortization, Part 2
Blog Entry #354

Welcome back to our discussion of the Java Goodies Loan Amount script. Having gone through the script's HTML in the previous post, we are now ready to put its JavaScript under the microscope.

Consider an amortizing loan
(1) whose principal is $1000 and
(2) with a yearly interest rate of 5% and
(3) with a period of one year.
The loan is repaid in twelve monthly installments; each payment is the same; the first payment is due one month after the loan start date. For each payment, the monthly interest on the principal balance is paid in full and the rest of the payment is applied to the principal balance. What is the monthly payment?

We enter 1000, 5, and 12 into the left frame's Loan Amount, Yearly Interest Rate, and Loan Period (in months) fields, which have LoanAmt, Rate, and Period name identifiers, respectively.

<label>Loan Amount ($)<br><input type="text" name="LoanAmt" size="10"></label> ...
<label>Yearly Interest Rate (%)<br><input type="text" name="Rate" size="10"></label> ...
<label>Loan Period (in months)<br><input type="text" name="Period" size="10"></label>


The label element has an (%inline;)* content model and therefore can validly contain a <br> line break.
• The Loan Amount should be a pure number and not begin with a currency symbol of some sort, so I've appended a ($) to the label text (I'll append one to the Payment field's label text as well, vide infra).
• The Yearly Interest Rate should be a pure number and expressed as a percentage (vis-à-vis a decimal fraction), so I've appended a (%) to the label text.

We click the button to the right of the Payment field.

<label>Payment ($)<br><input type="text" name="PaymentAmt" size="10"></label>
<input type="button" value="Calculate" onclick="CalcPayment(this.form);">


Clicking the button calls a CalcPayment( ) function and passes thereto a reference to the parent form (this.form), which is given a form identifier.

<script type="text/javascript">
var LoanAmt, Rate, Period, Payment;
function CalcPayment(form) { ... }


CalcPayment( ) first numberifies the LoanAmt.value, Rate.value, and Period.value strings as it'll be doing some math on them in just a bit.

LoanAmt = parseFloat(form.LoanAmt.value);
Rate = parseFloat(form.Rate.value);
Period = parseInt(form.Period.value);


The LoanAmt.value and Rate.value are parseFloat( )ed and the resulting values are assigned to the LoanAmt and Rate variables, respectively; the Period.value, for which an integer is expected, is parseInt( )ed and the resulting value is assigned to the Period variable. (FYI: parseInt( ) floors a floating-point number, e.g., a 12.5 input would be converted to 12.)

The parseFloat( ) and parseInt( ) functions both return NaN ("Not-A-Number") for non-numeric inputs. CalcPayment( ) accordingly uses a set of isNaN( ) gates to intercept any NaNs in the LoanAmt/Rate/Period data.

if (isNaN(LoanAmt)) { window.alert("Missing Loan Amount"); return; }
if (isNaN(Rate)) { window.alert("Missing Interest Rate"); return; }
if (isNaN(Period)) { window.alert("Missing Period Value"); return; }


What the above operations won't do is stop the user from inputting numbers with commas in them, e.g., a Loan Amount ($) of 1,000, which would be parseFloat( )ed to 1 - not what we want to happen, needless to say - however, test( )ing for the presence of such commas and replace( )ing them with empty strings is not at all difficult.

LoanAmt = /,/.test(form.LoanAmt.value) ? parseFloat(form.LoanAmt.value.replace(/,/g, "")) : parseFloat(form.LoanAmt.value);
/* The ?: conditional operator is documented here in the Mozilla JavaScript Reference. */


CalcPayment( ) next converts the Rate percentage into a more usable number as follows:
(1) If Rate is greater than or equal to 1 (and that's certainly going to be the case for most Rates), then it is divided by 100 in order to convert it to a decimal fraction.
(2) Without regard to its original value, Rate is subsequently divided by 12 in order to convert it to a monthly interest rate.

if (Rate >= 1) { Rate /= 100; }
Rate /= 12;
/* Division assignment is documented here. */


We are now ready to calculate the monthly Payment, and we do that by plugging LoanAmt, Rate, and Period into the following annuity formula, which is detailed and (not quite completely) derived in Wikipedia's "Amortization calculator" entry.

Payment = LoanAmt * (Rate * Math.pow(1 + Rate, Period)) / (Math.pow(1 + Rate, Period) - 1);

You would expect the Payment to be proportional to the LoanAmt and Rate, but the (1 + Rate)Period exponentiations, which are related to the total (principal + interest) cost of the loan, are admittedly not so intuitive.

For our example, the annuity formula gives us a Payment of 85.60748178846674, which is rounded up to the nearest cent with:

Payment = Math.ceil(Payment * 100) / 100;

We can more conveniently carry out the Payment truncation via the Number object's toFixed( ) method, which had not been implemented at the time that the script was written.

Payment = Payment.toFixed(2);

The last digit of the toFixed( ) return is rounded normally, i.e., it's increased by one if the digit after that is 5-9 and is left alone otherwise. As a result, the ceil( ) and toFixed( ) approaches will be off by a penny some of the time: that's life.

The formatted Payment is displayed in the Payment field, which has a PaymentAmt name identifier (vide supra).

form.PaymentAmt.value = Payment.toString( );

For this assignment, there is no need to invoke the toString( ) method as Payment is automatically converted from a number to a string by the JavaScript engine.

CalcPayment( ) concludes with an unnecessary return; statement, which returns undefined to the CalcPayment( ) call and causes the function to exit.

We'll go after the rest of the script's JavaScript in the following entry.

Thursday, November 19, 2015
 
Adventures in Amortization, Part 1
Blog Entry #353

Today we'll begin a discussion of "Loan Amount", the next Calendars, Clocks, and Calculators script. Authored by Dave Wedwick in 1998, the Loan Amount script provides an interface for working with amortizing loans, for example, mortgage loans, car loans, student loans, etc.

An amortizing loan has four basic, related parameters:
(1) a principal,
(2) an interest rate,
(3) a period, and
(4) a periodic (usually monthly) payment.
Typically, a lender sets the principal, interest rate, and period, and calculates a monthly payment for the lendee. The Loan Amount script enables the user to set any three of these parameters and calculate the remaining parameter; it can then generate a complete table of payments for the period.

A functioning demo for the Loan Amount script may be accessed here.

The script code and its frameset

The script display is in the form of a two-frame left-right frameset. On the loanamount.html page,
(a) a The frames page. link points to the frameset page,
(b) a Left frame page. link points to the right frame, and
(c) a Right frame page. link points to the left frame.
(Yes, the (b) link should point to the (c) target and vice versa.)
There are no separate pages for the script code, which must be fished out of the frameset/frame source.

Here's the frameset page code from start to finish:

<html>
<head>
<title>Loan Calculation and Amortization</title>
</head>
<frameset rows="100%" cols="250,*">
<frame name="Frame 1" src="calc.htm" scrolling="auto">
<frame name="Frame 2" src="amortize.htm" scrolling="auto">
</frameset>
</html>


• Per the frameset's cols attribute, the left frame has a width of 250px and the right frame takes up the rest of the page. Both frames have an effective height of 100%, i.e., they vertically extend to the bottom of the viewport.
• With a cols="250,*" arrangement, the rows="100%" setting is not meaningful and can be removed.
auto is the default value of the scrolling attribute: This value tells the user agent to provide scrolling devices for the frame window when necessary.

In a Non-conforming features section, HTML5 declares that the frame and frameset elements are entirely obsolete, and must not be used by authors. We will unframe the display in due course, but let's go with what we have for the time being.

The left frame

HTML

The calc.htm document body largely comprises a name="CalcForm" form, which holds four text inputs, one for each loan parameter. Each text input is preceded by a label (not marked up as such) and is followed by a push button. The form concludes with a separate push button. Each button is linked to a JavaScript function.

<body bgcolor="#ffffff">
<form name="CalcForm">
Loan Amount<br>
<input type="text" name="LoanAmt" size="10">
<input type="button" value="Calculate" onclick="CalcLoanAmt(this.form);">
<br><br>
...
Payment<br>
<input type="text" name="PaymentAmt" size="10">
<input type="button" value="Calculate" onclick="CalcPayment(this.form);">
<br><br>
<input type="button" value="Amortization Table" onclick="ShowAmoritazation(this.form);">
<br></form>
<!-- The last <br> has no effect rendering-wise, at least on my computer. -->


The form is coded and laid out straightforwardly: there are a few validation-related issues here that we could nitpick over but no red flags to speak of.

The left frame concludes with an email link credit:

<a href="mailto:dave@wedwick.com">Prepared by Dave Wedwick</a>
</body></html>


I suspect the dave@wedwick.com address is still live as wedwick.com itself is live.

JavaScript

A single <script> element in the calc.htm document head holds all of the script's JavaScript. The JavaScript contains
(a) top-level declarations for LoanAmt, Rate, Period, and Payment variables and
(b) six functions, namely, CalcPayment( ), CalcLoanAmt( ), CalcPeriod( ), CalcRate( ), ValToMoney( ), and ShowAmoritazation( ) (sic), in that order.

In the name of completeness, I should note that the <script> begins with
<!--
document.write("<!-- Hide the script -->");

and ends with
document.write("<!-- End hiding the script -->");
//-->
.
The write( ) commands are redundant and can be thrown out; for that matter, we shouldn't need the <!-- and //--> either in this day and age.

The right frame

The amortize.htm document body comprises a big Loan Calculator title

<body bgcolor="#ffffff"><center><br>
<font color="#0000ff" size="+3">Loan Calculator</font>


and two meta-information paragraphs that are oddly marked up as <table> elements, e.g.:

<br><br><br>
<table width="50%"><tr>
<td bgcolor="#cacaca">This will calculate the amortization table for the parameters to the left. Fill in any three and press <b>Calculate</b> to calculate the fourth value. Click the <b>Amortization Table</b> button to create the amortization table.</td>
</tr></table>


The Loan Calculator text is semantically a heading and the size="+3" attribute gives it the size of an <h1> heading, so let's mark it up as an <h1> element, shall we?

h1 { text-align: center; color: blue; }
/* The original <font> text is not bolded - add a font-weight:normal; declaration if you like. */

<h1>Loan Calculator</h1>


As for those paragraphs, we should really code them as <p> elements, yes?
(I don't like the grayish #cacaca background color so I'm changing it to #ccffcc.)

p { width: 50%; margin-left: auto; margin-right: auto; background-color: #ccffcc; }

<p>This will calculate the amortization table ...</p>


We'll start going through the script's JavaScript via an example in the following entry.

Thursday, November 05, 2015
 
Numbers That Self-Multiply and How to Deal with Them
Blog Entry #352

Next up in the Java Goodies Calendars, Clocks, and Calculators sector is a "Square Root in the Status Bar" script, which we will discuss in today's entry. Authored by Tom Hammond in 1998, the Square Root in the Status Bar script determines the (principal) square root of a user-inputted number and then writes the root to the browser window's status bar. The script code may be accessed at Joe's JavaScript Goodies site.

You'll need an old-school browser to see the script's effect because modern browser windows do not have status bars; we'll route the root to a more suitable holder in due course.

(As we'll see below, the statusroot.txt code is pretty simple; however, every script has a story that deserves to be told, does it not? More importantly, when I come across one of these scripts whose output is problematic in some way, I can't let that sit, I've just got to do something about it - that's how I roll, and that's why I'm writing this post.)

The script

The script's renderable part (there's no clear demarcation between the document head and body) begins with some instructions for the user:

<center>
<i><big><b>Instructions:</big></i><br>
First of all enter a number into the text box, then click the 'Square Root' button and look at the little status bar at the bottom of the screen to see what the square root of the number you entered is!


• To horizontally center the script display (my demo below is left-justified), use a <div style="text-align:center;"> ... </div> container as opposed to a <center> element.
• To enlarge the Instructions: font size, use a <span style="font-size:larger;"> ... </span> container as opposed to a <big> element.
• Note that the </b> tag is missing.

The instructions are followed by a name=feedbackForm form

<form name="feedbackForm">
<input type="text" name="number" value="" size="8">
<input type="button" value="Square Root" onclick="display( );">
</form></center>


that contains
(1) a name=number text input in which the user enters a number to be square-rooted and
(2) a button that when clicked calls a display( ) function

<script language="javascript"> function display(number) { window.status = "The square root of " + document.feedbackForm.number.value + " is " + Math.sqrt(document.feedbackForm.number.value); } </script>

that Math.sqrt( )s the number field's value, appends the sqrt( ) return to a

The square root of document.feedbackForm.number.value is

string, and loads the resulting string into the status bar if the status bar is present.

• The display( ) function's number parameter is unnecessary: it fortunately doesn't affect the document.feedbackForm.number.value getter although you should still get rid of it.

Modifications

The display( )-containing <script> element includes a readme-type comment that concludes with:

/* If anyone has any ideas, use 'em! */

Let's do that, shall we?

A new home

Obviously, the sqrt( ) return should be written to the page vis-à-vis the status bar, and a <samp> element is a semantically appropriate place to park it:

Your square root is: <samp id="rootSamp"></samp>
...
document.getElementById("rootSamp").textContent = Math.sqrt(document.feedbackForm.number.value);


Nonnegative numbers only, please

The sqrt( ) method returns NaN for arguments that are not nonnegative numbers; I prefer to intercept such arguments before the fact:

var rInput = document.feedbackForm.number; if (isNaN(rInput.value) || rInput.value === "") { window.alert("Please enter a nonnegative number into the text box."); rInput.value = ""; rInput.focus( ); return; } if (rInput.value < 0) { window.alert("Nope, we're not gonna generate an imaginary number for you.") rInput.value = ""; rInput.focus( ); return; }

• Regarding the first if statement, the isNaN(rInput.value) subcondition flags all non-numeric values (including true and false, null, and undefined) except for the empty string with the OS X browsers on my computer; a rInput.value === "" subcondition is necessary to intercept a blank number field.
• It is left to the reader as an exercise to have the script output an imaginary number for a negative number input.

A truncated root

The following code will stop a sqrt( ) return at three places past the decimal point if it goes beyond that:

var root = Math.sqrt(rInput.value);
if (/\.\d{4,}$/.test(root)) root = root.toFixed(3);
document.getElementById("rootSamp").textContent = root;


The \.\d{4,}$ regular expression matches a floating-point number having four or more post-decimal point digits; if the root test( )-matches the expression, then it is toFixed( ) at the thousandths place.

Demo

It's time to roll out a demo - try it out with any input you like.

Instructions:
(1) Enter a nonnegative number (either an integer or a floating-point number) into the text box.
(2) Click the 'Square Root' button to display the square root of your entered number to three or fewer places past the decimal point.

Your square root is:

Other extractions

Before wrapping up this post, I should note that the JavaScript Math object has a pow( ) method via which we can determine the square root or any other type of nth root (a cube root, a fourth root, etc.) of a number - check out the Examples on the Mozilla Math.pow( ) page.
We'll take on something a bit more challenging next time, I promise.


Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)