This is an old blog. My new blog is moved here.

Savings calculator compound interest as jQuery plugin: OO JavaScript showcase

1/28/2010

It looks like nobody has written a jQuery plugin Savings calculator for compound interest, so here is one.

This time I really did my best to showcase the best jQuery plugin authoring best practices: all possible options are exposed, including HTML templates. The plugin even has an option to return pure data object, which lets you create your own markup from scratch.

In Particular, I have fallen in love with the two small utility functions here: StringBuilder, "sub string templator" which merges object and string in the MVC manner.

(function($) {

//util framework
var lib = {
StringBuilder: function() {
var s = [];
return {
append: function(v) {
if (v) {
s.push(v);
}
},
clear: function() {
s.length = 1;
},
toString: function() {
return s.join("");
}
}
},
template: function(m, v) {
v = v.replace(/\{[^\}]*\}/g, function(key) {
return m[key.slice(1, -1)] || '';
});
return v;
},
formatNumber: function(n) {
return Number(n).toFixed(2);
}
}

//calculator results in string
var buildTable = function(data, _op) {

var sb = lib.StringBuilder();

//header template
sb.append(_op.template.header);

for (var i = 0, l = data.length; i < l; i++) {

//alt row swhitch
if (i % 2) {
//repeat
sb.append(lib.template(data[i], _op.template.repeat));
}
else {
//repeat alt row
sb.append(lib.template(data[i], _op.template.repeatAlt));
}
}

//footer template
sb.append(_op.template.footer);

return sb.toString();

}

//creates summary object
var summaryData = function(data, _op) {

var amountInvested = (data.length * _op.monthlyAmount) + _op.initialDepost;

var totalAmount = data[data.length - 1].currentAmount;

return {
totalAmount: totalAmount,
totalAmountInvested: amountInvested,
earnedInterest: lib.formatNumber(totalAmount - amountInvested)
}
}

//calculator ouput data
var dataCalc = function(obj) {

var _data = [];

//some pre-calcs
var mRate = (obj.interestRate / 100) / 12;
var numberOfMonths = obj.numberOfYears * 12;

//Get a decimal
var currentAmount = 0.1 - 0.1;
var currentContributions = 0.1 - 0.1;
var currentInterest = 0.1 - 0.1;

currentAmount += obj.initialDepost; //initial depost
currentContributions += obj.initialDepost;

//amort table loop
var currentMonth = 0;
while (currentMonth < numberOfMonths) {

currentMonth++;

var interest = Number(currentAmount) * Number(mRate);

currentInterest = Number(currentInterest) + Number(interest);
currentContributions = Number(currentContributions) + obj.monthlyAmount;
currentAmount = Number(currentAmount) + Number(interest) + obj.monthlyAmount;

//gets table in row format
_data[currentMonth - 1] = {
currentContributions: lib.formatNumber(currentContributions),
currentInterest: lib.formatNumber(currentInterest),
currentAmount: lib.formatNumber(currentAmount),
currentMonth: currentMonth
};
}

//final bild out:
return _data;
}


// plugin definition
$.fn.savingsCalculator = function(op) {

// build main options before element iteration
var _op = $.extend({}, $.fn.savingsCalculator.defaults, op);

// iterate and reformat each matched element
return this.each(function() {

var T = $(this); //selected element
var o = $.meta ? $.extend({}, _op, $this.data()) : _op; // build element specific options

//final insert

//gets data in object
var _data = dataCalc(_op);

//builds HTML table
var _tableHtml = buildTable(_data, _op);

//summary HTML
var _summaryHtml = lib.template(summaryData(_data, _op), _op.template.summary);

T.html(_summaryHtml + _tableHtml);

});
};

//gets row data
$.savingsCalculatorData = function(op) {

// build main options before element iteration
var _op = $.extend({}, $.fn.savingsCalculator.defaults, op);

var _data = dataCalc(_op);

return {
table: _data,
summary: summaryData(_data, _op)
};
}

//defaults
$.fn.savingsCalculator.defaults = {
initialDepost: 0,
interestRate: 5,
numberOfYears: 1,
monthlyAmount: 100,
template: {
summary: "<p>Total amount at the end of the term: {totalAmount}<br />Total amount invested: {totalAmountInvested}<br />Interest earned: {earnedInterest}</p>",
header: "<table class=\"data_table\"><tr><th>Month</th><th>Contributions</th><th>Interest</th><th>Total</th></tr>",
repeat: "<tr><td>{currentMonth}</td><td>{currentContributions}</td><td>{currentInterest}</td><td>{currentAmount}</td></tr>",
repeatAlt: "<tr class=\"alt\"><td>{currentMonth}</td><td>{currentContributions}</td><td>{currentInterest}</td><td>{currentAmount}</td></tr>",
footer: "</table>"
}
};

})(jQuery);

And here is how you use it:

$("#calc").savingsCalculator({
initialDepost: 1000,
interestRate: 5,
numberOfYears: 1,
monthlyAmount: 100
});

Or you can just get the data object like this:

console.log($.savingsCalculatorData()); 

Responses to The Savings calculator compound interest as jQuery plugin: OO JavaScript showcase