reptile7's JavaScript blog
Monday, January 18, 2016
Adventures in Amortization, Part 6
Blog Entry #358

At this point, we have gone through the Loan Amount script's code in its entirety. There are two outstanding coding issues that I want to address before we move on:

(1) As noted in Part 1 of this series, the frameset and frame elements are now obsolete. I'd say it behooves us to come up with an alternate way to structurally demarcate the left and right content areas of the script display, wouldn't you?

(2) As detailed in the previous post, the script's ShowAmoritazation( ) function extensively commingles HTML and JavaScript. Maybe we should disentangle that stuff, huh?

New divisions

The obvious way to bring the display layout up to date is to exchange the frame/set structure for a pair of absolutely positioned divs.

#leftDiv, #rightDiv { position: absolute; height: 100%; }
#leftDiv { width: 250px; border-right: solid 2px black; }
#rightDiv { left: 250px; }
h1 { color: blue; text-align: center; }

<div id="leftDiv">
<form name="CalcForm" action=""> ... </form>
<div id="rightDiv">
<h1>Loan Calculator</h1> ...

border-right: solid 2px black; mimics the original interframe border.

Alternatively, we can exchange the frame/set structure for a pair of inline-block-displayed divs.

#leftDiv, #rightDiv { display: inline-block; height: 100%; }
#leftDiv { width: 20%; border-right: 2px solid black; }
#rightDiv { width: 75%; vertical-align: top; }

• I find that the rightDiv div must be given a specific, less-than-the-available-space width in order to place it in the leftDiv div's line box; upon doing that, a vertical-align: top; declaration is necessary to vertically align the tops of the divs.

For my demo below, the former approach proved problematic (not surprising, as you wouldn't expect the absolute positioning to play well with the rest of the page) but the latter approach worked fine.

Tables to table

Rather than create the entire amortization table on the fly, I prefer to use the ShowAmortization( ) function (let's spell it right, shall we?) to only fill in the loan-specific parts of the table and otherwise code the static parts of the table as normal HTML. I'll put the table HTML in a zeroed-out tableDiv1 div that lies just outside the rightDiv div and later copy that HTML to a tableDiv0 div that lies just inside the rightDiv div:

#tableDiv1 { display: none; }

<div id="rightDiv">
...h1 and p elements...
<div id="tableDiv0"></div>
<div id="tableDiv1">
...table HTML...

document.getElementById("tableDiv0").innerHTML = document.getElementById("tableDiv1").innerHTML;

N.B. My tableDiv0 div/innerHTML procedure limits the display to a single table. In contrast, the original code allows the user to display any number of tables on the page: after one table is printed out, successively clicking the button (with or without changing the loan parameter values) appends more tables to that table in the absence of reloading the page, and I don't like that.

For my table HTML, I'm going to use one big table element with bona fide thead, tbody, and tfoot sections rather than separate table elements for the head and body/foot sections of the display.


table { margin-left: auto; margin-right: auto; width: 70%; }
td { text-align: center; width: 20%; }
p, .inputTd { background-color: #ccffcc; }

<table cellspacing="2" cellpadding="2">
<tr><td>Loan Amount</td>
<td id="loanamtTd" class="inputTd"></td>
<td id="periodTd" class="inputTd"></td></tr>
<tr><td>Interest Rate</td>
<td id="rateTd" class="inputTd"></td>
<td>Monthly Payment</td>
<td id="paymentTd" class="inputTd"></td></tr>
<tr><td colspan="5"><hr></td></tr>

• The table is horizontally centered within the tableDiv0 div by the margin-left: auto; margin-right: auto; declaration set and its width is set to 70% of the div's width.
• The table contents are horizontally and vertically pushed apart slightly by cellspacing="2" and cellpadding="2" attributes.
• The cell contents are horizontally centered and the cells themselves are given uniform widths.
• As noted earlier, I don't like the #cacaca background color so I'm changing it to #ccffcc.
• The <hr> head/body section break could be placed in either the thead or the tbody: the former strikes me as more appropriate.

Loading the vetted LoanAmt, Period, Rate, and Payment data respectively into the loanamtTd, periodTd, rateTd, and paymentTd cells is as easy as one, two, three (, four, five):

document.getElementById("loanamtTd").textContent = "$" + LoanAmt;
var monthString = Period == 1 ? " month" : " months";
document.getElementById("periodTd").textContent = Period + monthString;
document.getElementById("rateTd").textContent = (Rate * 1200).toFixed(3) + "%";
document.getElementById("paymentTd").textContent = "$" + Payment;


<tbody id="dataTbody">

• The header row is the only static part of the table body so that's all we need to code at this point. The headers are horizontally centered as per their default rendering.

We can build the data part of the tbody with:

for (Counter = 1; Counter <= Period; Counter++) { ...Interest/TotInterest/Principal/Bal calculations... dataTr = document.createElement("tr"); document.getElementById("dataTbody").appendChild(dataTr); dataArray = [Counter, Payment.toFixed(2), Interest.toFixed(2), Principal.toFixed(2), Bal.toFixed(2)]; for (var i = 0; i < dataArray.length; i++) { dataTd = document.createElement("td"); dataTr.appendChild(dataTd); dataTd.textContent = dataArray[i]; } }

• The rows and cells are created from scratch via the Document.createElement( ) method and are put in place via the Node.appendChild( ) method.
• The dataArray array of column content expressions (Counter, Payment.toFixed(2), etc.) enables us to iteratively load the expressions' values into the corresponding cells of each row.
• The cell contents are horizontally centered as per the td { text-align: center; width: 20%; } style rule (vide supra).


<tr><td colspan="5"><hr></td></tr>
<tr><td colspan="2">Total Interest</td><td id="totinterestTd"></td></tr>

document.getElementById("totinterestTd").textContent = TotInterest.toFixed(2);

'Nuff said.


Pre-demo note:
This blog makes use of an older Blogger template whose implementation of JavaScript is somewhat buggy. For whatever reason, the demo of this section only works in part at the main page - specifically with respect to the demo JavaScript, the CalcPayment( )/CalcLoanAmt( )/CalcPeriod( )/CalcRate( ) functionality is A-OK but the ShowAmortization( ) function doesn't write out the amortization table - however, there are no problems at all at the individual post page. If you're at the main page, click the button below to access the Demo section of the adventures-in-amortization-part-6.html page in a new window; if you're at the adventures-in-amortization-part-6.html page, you're good to go.

So, you're buying a $250,000 house via a 30-year mortgage with a 3.50% yearly interest rate. If your mortgage lender can't be bothered to give you a schedule of loan payments, you can rustle one up right here.

Loan Calculator

On the left-hand side, enter values into any three fields: to obtain the missing value, click its button. Subsequently, click the button to create an amortization table for your inputs; the table will appear below.

It may take a moment to create the amortization schedule after clicking the button. Please be patient!

Comments: Post a Comment

<< Home

Powered by Blogger

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