How to Create a Loan Amortization Calculator Using HTML and JavaScript

Published: October 30, 2011

Edited: 12 May 2015


JavaScript: HTML on Steroids
JavaScript: HTML on Steroids

So you have learned a little about HTML and JavaScript. Now you would like to accomplish something useful. If you make payments on any kind of loan or are thinking of taking one out then a javascript loan amortization calculator may fit your needs quite nicely.

This final JavaScript tutorial in the installment of tutorials puts together disciplines learned in many of Dumbledore's previous tutorials and leads an aspiring programmer on the quest to develop a functioning loan amortization calculator.

Unlike Dumbledore's other HTML and JavaScript tutorials that simply include snippets of the elements under study, this module will present the entire set of source code components, both HTML and JavaScript necessary to build the amortization calculator.

HTML Input Table

The only component of the amortization calculator that users directly interact with is the HTML input table. This table provides a HTML form where the user may enter the data used to calculate the characteristics of the loan's terms and perform the amortization. The operations are then completed when the user clicks on the button labeled Commit.

The following code module presents the entire HTML file for the amortization program:

HTML Table Code

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

  <head>
    <title>Amortization Calculator</title>
    <style>
      body {background-color:white; font-family: Arial, Helvetica, sans-serif}
      h2 {color:blue; letter-spacing: 1em; font-size: 1.5em; text-align: center}
      input {color:blue; margin-left: 15px}
      td {text-align:center; background-color:yellow}
    </style>

    <script type="text/javascript" src="amort.js"></script>

  </head>

  <body>

    <center>
      <div id="mainForm">
        <form id="form1" name="form1">
          <table>
            <tr><td> Your name</td>
              <td><input id="name" name="name" size="35" /></td>
            </tr>
            <tr><td> Loan Amount</td>
              <td><input id="amount" name="amount" size="8" /></td>
            </tr>
            <tr><td> Interest Rate</td>
              <td><input id="rate" name="rate" size="5" /></td>
            </tr>
            <tr><td> Number of Payments</td>
              <td><input id="numPay" name="numPay" size="5" /></td>
            </tr>
            <tr><td></td>
              <!-- Clicking the Commit button invokes the commitData() function in the <script> section above -->
              <td><input type="button" onclick="commitData()" value="Commit" /></td>
            </tr>
          </table>
        </form>
      </div>
    </center>
  </body>
</html>

Separate HTML and JavaScript

The HTML code presented above represents all the HTML coding necessary for the Amortization Program. Since HTML is only used by the program to generate the input for the program and display the results of the amortization, Dumbledore separated the HTML and JavaScript code.

The JavaScript component is contained in a separate file named amort.js and the following line of code included in the header portion of the HTML code above illustrates how to refer to the external JavaScript file from the HTML code:

 <script type="text/javascript" src="amort.js"></script>

Amortization: JavaScript By The Numbers

As stated earlier, Dumbledore included the JavaScript code for the amortization program in a separate file. This serves a couple of purposes: first, separating the HTML and JavaScript isolates the presentation of data from the program logic; second, the JavaScript does not show up in the source-code for the HTML document.

The modules that follow present each of the JavaScript functions and explain what goes on within the function modules. The individual modules are presented as code snippets and the entire JavaScript file is included at the end of the tutorial. The first of these modules is the commitData() function:

The commitData() Function

The commitData() function is the control or dispatch module for the program. This is the function that the user calls by pressing the button labeled Commit in the HTML form and specified in the <input> element of the HTML code. There are a number of housekeeping routines initiated by this function, the first of which is to create a table on a new page and echo the data that the user supplied. The module is displayed below:

function commitData() {
  // Declair and initialize the variables
  var loanName=document.form1.name.value;
  var loanAmount=document.form1.amount.value;			
  var intRate=document.form1.rate.value; 			
  var numPay=document.form1.numPay.value;
  // Render the display tables to echo the user input
  renderEchoInput();  
  	
  // Render the amortization table, this table displays the number of
  // rows specified by the number of payments input by the user in the numPay field.
  renderAmortizationTable(numPay);
  
  // Echo the input in the display table using the displayTableField() function
  displayTableField("flname",loanName);
  displayTableField("lamount",loanAmount);
  displayTableField("irate",intRate);
  displayTableField("numPmt",numPay);
  //Calculate and display the monthly payment amount
  var monPmt=calcMonthly(loanAmount,numPay,intRate);
  displayTableField("monPmt",monPmt);
  // Call the amortization routine
  amortizePmts(loanAmount,intRate,numPay,monPmt);
  return;
}

The commitData() function is a dispatcher module, which simply means that this function calls other functions to perform the actions necessary for the program to generate the desired results, in this case the loan amortization.

This function begins by declaring and initializing the variables necessary to retrieve the user's data from the HTML form.

The function then calls the functions that echo the user's input back so the user may see what was entered, this is the renderEchoInput() function. Next, the function to render the amortization table is called, which is the renderAmortizationTable() function.

The displayData() function is called four times to echo back the data the user entered and finally the functions to calculate the terms of the loan and perform the amortization are called.

The functions called by the commitData() function comprise the meat of the program and the remainder of this hub explains each of those functions.

Render the Table to Echo Input

function renderEchoTable(){
  document.write("<table>");
  document.write("<tr><td><table id='datTab'>");
  document.write("<tr><td id='namLab'>Borrower Name: </td><td id='flname'></td></tr>");
  document.write("<tr><td id='amtLab'>Loan Amount: </td><td id='lamount'></td></tr>");
  document.write("<tr><td id='intLab'>Interest Rate: </td><td id='irate'></td></tr>");
  document.write("<tr><td id='numLab'>Number of Payments:   </td><td id='numPmt'></td></tr>");
  document.write("<tr><td id='monLab'>Monthly Payment: </td><td id='monPmt'></td></tr>");
  document.write("</table></td>");
}

The purpose of the renderEchoTable() function is to simply create the table that will display back the information entered by the user for verification. The commitData() function calls this function exactly one time.

You may notice that the function simply contains a number of document.write statements and that those statements seem to contain HTML code. If you noticed this, you are correct. JavaScript may contain HTML code. This is a useful characteristic when the programmer wishes to create HTML elements after the initial web page loads. This is exactly what the author wished to accomplish with this function. The function createss an empty table, which the program will later populate with data.

After creating the echo table, the amortization table is created as determined by the number of payments that the user entered:

Amortization Program output  with Table Headings
Amortization Program output with Table Headings

Render the Amortization Table

Like the renderEchoTable() function above, the renderAmortizationTable() function displays an empty table that the program will later populate. The major difference in the functionality of the two modules is that this table varies in length according to a value entered by the user.

This variation is accomplished using a looping structure, which is dependent on the numPay parameter supplied by the calling routine.

One innovative method included in this function is using the tagNam variable to create dynamic id's for the <td> elements within the code. These id's are used by the getElementById() function later in the program so they must be unique. An alternative to the dynamic id's would have been to hard code an HTML table representing the maximum length of a loan, say 30 years or 360 payments but this would entail creating 360 static rows in the HTML table. This would have been a tedious exercise in codingcoding. However, in some cases the tedious method may someimes be easier than figuring out the alternative. Which method to apply isd up to the coder developing the program.

function renderAmortizationTable(numPay) {
  document.write("<td><table border="+"1"+" id='pmtTab'><tr   style='background-color:DeepSkyBlue'><td id='numHead'>Payment Number</td><td id='oldBal'>Previous Balance</td><td id='pt'>Payment</td><td id='oil'>Interest Paid</td><td id='newBal'>New Balance</td><td id='til'>Total Interest</td></tr>");
  var tagNam;
  for(var i=1;i<=numPay;i++) {
    loopNum=i;
    tagNam="n"+loopNum.toString(10);
    document.write("<tr style='background-color:LightSkyBlue'><td id=tagNam>"+i+"</td>");
    tagNam="b"+loopNum.toString(10);
    document.write("<td id="+tagNam+"></td>");
    tagNam="p"+loopNum.toString(10);
    document.write("<td id="+tagNam+"></td>")  
    tagNam="oi"+loopNum.toString(10);
    document.write("<td id="+tagNam+"></td>");
    tagNam="nb"+loopNum.toString(10);
    document.write("<td id="+tagNam+"></td>");
    tagNam="ti"+loopNum.toString(10);
    document.write("<td id="+tagNam+"></td></tr>");
  }
  // This statement outside the loop completes the table
  document.write("</table></td></tr></table>");
}

Amortize Payments

The amortizePmts() function performs the steps to amortize the loan. These steps include calculating the current interest due on the loan, subtracting that interest from the amount of the monthly payment, then subtracting the resulting amount from the old balance. The result of this final subtraction then becomes the new balance for the loan. These operations repeat for as many payments are included in the terms of the loan and the final result is the loan amortization.

function amortizePmts(loanAmount,intRate,numPay,monPmt) {
  var oldBalance=loanAmount;
  var newBalance=loanAmount;				
  intRate=(intRate/100)/12;				
  var monthly=monPmt;
  var owedInterest=0;
  var totalInterestPd=0;
  var tagNam;
  var dispInt
  // The for loop performs the amortization
  for(var i=1;i<=numPay;i++) {
    var loopNum=i;
    owedInterest=newBalance*intRate;
    dispInt=twoDecimal(owedInterest);
    totalInterestPd=totalInterestPd+owedInterest;
    // Test for the final payment
    if (i<numPay) {
      monthly=twoDecimal(monPmt-dispInt);
      oldBalance=newBalance;
      newBalance=twoDecimal(oldBalance-monthly);
    }
    else {
      monthly=(oldBalance-monthly)+owedInterest;
      oldBalance=newBalance;
      newBalance=0;
      monthly=twoDecimal(monthly);
    }
    tagNam="b"+loopNum.toString(10);
    displayTableField(tagNam,oldBalance);
    tagNam="p"+loopNum.toString(10);
    displayTableField(tagNam,monthly);
    tagNam="oi"+loopNum.toString(10);
    displayTableField(tagNam,dispInt);
    tagNam="nb"+loopNum.toString(10);
    displayTableField(tagNam,newBalance);
    tagNam="ti"+loopNum.toString(10);
    displayTableField(tagNam,twoDecimal(totalInterestPd));
  }
  return;
}
Amortization output reflecting input data
Amortization output reflecting input data

Display a Table Field

The displayTableField() function is the shortest function in the program and was created as an early demonstration of the benefits of modularization. The two attributes included in the definition of the function are passed to the function when it is invoked and this short routine actually eliminates quite a bit of redundant coding by shortening the lengths of the lines used to display a table field if the function were not a separate module.

function displayTableField(eleId,eleDat) {
  document.getElementById(eleId).innerHTML=eleDat;
  return;
}

Are tutorials worthwhile

Did you view Dumbledore's other tutorials?

  • Yes
  • No
  • There were other tutorials?
See results without voting

Calculate the Monthly Payment

A standard accounting function forms the basis for the function used to calculate the monthly payment. This function uses the amount of the loan, the interest rate, and the number of payments to determine what the monthly payment would be for the given terms of the loan. The payment is calculated one time then echoed back to the user and finally used by the amortization routine to specify the state of the loan after each payment is made.

function calcMonthly(principal,numPay,intRate) {
  var monthly;
  var intRate=(intRate/100)/12;
  var principal;
  // The accounting formula to calculate the monthly payment is
  //	M = P * ((I + 1)^N) * I / (((I + 1)^N)-1)
  // The following code  transforms the accounting formula into JavaScript to calculate the monthly payment
  monthly=(principal*(Math.pow((1+intRate),numPay))*intRate/(Math.pow((1+intRate),numPay)-1));
  return twoDecimal(monthly);
}

Convert a Format to Two-Decimal

When interest rates are calculated they generally extend out to quite a few decimal places. This floating point number then influences monetary calculations so the number of decimal places may become quite large.

The twoDecimal() function converts a floating point number to one limited to two decimal places. This function is necessary to convert the output to a more readable form and ensure that the output in fact fits in the table fields..

function twoDecimal(chgVar) {
  var chgVar;
  var twoDec=chgVar.toFixed(2);
  return twoDec;
}

Was this hub informational?

The author appreciates all comments.

Disclaimer

Note: The code contained in this hub contains some minor errors, which are left to the learner to discover and correct as an exercise. Therefore, no warranty, implied or otherwise, is supplied as a guarantee for this code. The program was created and presented as a learning exercise.

The Complete amort.js file

function commitData() {
  // Declair and initialize the variables
  var eleId;
  var eleDat;
  var loanName=document.form1.name.value;
  var loanAmount=document.form1.amount.value;			
  var intRate=document.form1.rate.value; 			
  var numPay=document.form1.numPay.value;
  var loopNum;
  var tagNum;
  var tagNam;
  // Render the display tables to echo the user input
  document.write("<table>");
  document.write("<tr><td><table id='datTab'>");
  document.write("<tr><td id='namLab'>Borrower Name: </td><td id='flname'></td></tr>");
  document.write("<tr><td id='amtLab'>Loan Amount: </td><td id='lamount'></td></tr>");
  document.write("<tr><td id='intLab'>Interest Rate: </td><td id='irate'></td></tr>");
  document.write("<tr><td id='numLab'>Number of Payments:   </td><td id='numPmt'></td></tr>");
  document.write("<tr><td id='monLab'>Monthly Payment: </td><td id='monPmt'></td></tr>");
  document.write("</table></td>");		
  // Render the amortization table, this table displays the number of
  // rows specified by the number of payments input by the user in the numPay field.
  document.write("<td><table border="+"1"+" id='pmtTab'><tr style='background-color:DeepSkyBlue'><td id='numHead'>Payment Number</td><td id='oldBal'>Previous Balance</td><td id='pt'>Payment</td><td id='oil'>Interest Paid</td><td id='newBal'>New Balance</td><td id='til'>Total Interest</td></tr>");
  for(var i=1;i<=numPay;i++) {
    loopNum=i;
    tagNam="n"+loopNum.toString(10);
    document.write("<tr style='background-color:LightSkyBlue'><td id=tagNam>"+i+"</td>");
    tagNam="b"+loopNum.toString(10);
    document.write("<td id="+tagNam+"></td>");
    tagNam="p"+loopNum.toString(10);
    document.write("<td id="+tagNam+"></td>")  
    tagNam="oi"+loopNum.toString(10);
    document.write("<td id="+tagNam+"></td>");
    tagNam="nb"+loopNum.toString(10);
    document.write("<td id="+tagNam+"></td>");
    tagNam="ti"+loopNum.toString(10);
    document.write("<td id="+tagNam+"></td></tr>");
  }
  // This statement outside the loop completes the table
  document.write("</table></td></tr></table>");
  // Echo the input in the display table using the displayTableField() function
  displayTableField("flname",loanName);
  displayTableField("lamount",loanAmount);
  displayTableField("irate",intRate);
  displayTableField("numPmt",numPay);
  //Calculate and display the monthly payment amount
  var monPmt=calcMonthly(loanAmount,numPay,intRate);
  displayTableField("monPmt",monPmt);
  // Call the amortization routine
  amortizePmts(loanAmount,intRate,numPay,monPmt);
  return;
}

function amortizePmts(loanAmount,intRate,numPay,monPmt) {
  var oldBalance=loanAmount;
  var newBalance=loanAmount;				
  intRate=(intRate/100)/12;				
  var monthly=monPmt;
  var owedInterest=0;
  var totalInterestPd=0;
  var tagNam;
  var dispInt
  // The for loop performs the amortization
  for(var i=1;i<=numPay;i++) {
    var loopNum=i;
    owedInterest=newBalance*intRate;
    dispInt=twoDecimal(owedInterest);
    totalInterestPd=totalInterestPd+owedInterest;
    // Test for the final payment
    if (i<numPay) {
      monthly=twoDecimal(monPmt-dispInt);
      oldBalance=newBalance;
      newBalance=twoDecimal(oldBalance-monthly);
    }
    else {
      monthly=(oldBalance-monthly)+owedInterest;
      oldBalance=newBalance;
      newBalance=0;
      monthly=twoDecimal(monthly);
    }
    tagNam="b"+loopNum.toString(10);
    displayTableField(tagNam,oldBalance);
    tagNam="p"+loopNum.toString(10);
    displayTableField(tagNam,monthly);
    tagNam="oi"+loopNum.toString(10);
    displayTableField(tagNam,dispInt);
    tagNam="nb"+loopNum.toString(10);
    displayTableField(tagNam,newBalance);
    tagNam="ti"+loopNum.toString(10);
    displayTableField(tagNam,twoDecimal(totalInterestPd));
  }
  return;
}

function displayTableField(eleId,eleDat) {
  document.getElementById(eleId).innerHTML=eleDat;
  return;
}

function calcMonthly(principal,numPay,intRate) {
  var monthly;
  var intRate=(intRate/100)/12;
  var principal;
  // The accounting formula to calculate the monthly payment is
  //	M = P * ((I + 1)^N) * I / (((I + 1)^N)-1)
  // The following code  transforms this accounting formula into JavaScript to calculate the monthly payment
  monthly=(principal*(Math.pow((1+intRate),numPay))*intRate/(Math.pow((1+intRate),numPay)-1));
  return twoDecimal(monthly);
}

function twoDecimal(chgVar) {
  var chgVar;
  var twoDec=chgVar.toFixed(2);
  return twoDec;
}

More by this Author


Comments 6 comments

Dumbledore profile image

Dumbledore 4 years ago from Somewhere in Ohio Author

Boss,

You can use the isnumeric keyword to validate a required field that must be numeric. If the test passes, then data was entered into the field.

You can validate the value using the following:

if (number


Boss 4 years ago

Can you help me out with validation as a required field, Must be a Number Field, Number must be greater than 0.

Thank You.


Patel 4 years ago

Amazing


Dumbledore profile image

Dumbledore 5 years ago from Somewhere in Ohio Author

I'm glad I could help you, YellowOC1.


YellowOC1 profile image

YellowOC1 5 years ago

Nice tips, helped me out in working this new project


BABYCHICOSREVEIWS profile image

BABYCHICOSREVEIWS 5 years ago from Fort Pierce Florida

I thought I knew it all, amazing review. Thank you

    Sign in or sign up and post using a HubPages Network account.

    0 of 8192 characters used
    Post Comment

    No HTML is allowed in comments, but URLs will be hyperlinked. Comments are not for promoting your articles or other sites.


    Click to Rate This Article
    working