The Code
// Get the values from the user
function getValues() {
// get the values from the user
let amount = document.getElementById('loan').value
let term = document.getElementById('term').value
let interest = document.getElementById('interestRates').value
// convert the values to integers
amount = parseFloat(amount)
term = parseInt(term)
interest = parseFloat(interest)
// chek if the numbers are valid numbers
if (isNaN(amount) || isNaN(term) || isNaN(interest)) {
Swal.fire({
icon: 'error',
title: 'Oops!',
text: 'Please enter valid numbers into the form.',
backdrop: false,
})
} else if (amount < 0 || term < 0 || interest < 0) {
Swal.fire({
icon: 'error',
title: 'Sorry!',
text: 'Please enter positiv valid numbers.',
backdrop: false,
})
} else if (interest > 30) {
Swal.fire({
icon: 'error',
title: 'Oh no!',
text: 'The interest is too big, you need a lawyer.',
backdrop: false,
})
} else {
let allPayment = totalPayment(amount, interest, term)
displayCard(allPayment)
let monthlyAmount = totalMonthlyPayment(
amount,
interest,
term,
allPayment.payment
)
displayTable(monthlyAmount)
}
}
// interest rate
function interestRates(rate) {
let interest = rate / 1200
return interest
}
// claculate the monthly payment
function totalPayment(amount, rate, term) {
// the total monthly payment
let payment =
(amount * interestRates(rate)) /
(1 - (1 + interestRates(rate)) ** -term)
// the total cost
let totalCost = payment * term
// the total interest
let totalInterest = totalCost - amount
// create a new object with the value
let payments = {
amount: amount,
payment: payment,
interestRate: totalInterest,
cost: totalCost
}
// returning the object
return payments
}
// calculate result for each month
function totalMonthlyPayment(amount, rate, term, monthlyPayment) {
// creating an empty array to hold the objects
let resultsArray = []
// the remaining balance
let remainingBalance = amount
let totalInterest = 0
// iterate through the months and make calculation
for (let month = 1; month <= term; month++) {
// interest to pay
let interest = remainingBalance * interestRates(rate)
let amountPayment = monthlyPayment - interest
totalInterest += interest
// update the balance for the next iteration
remainingBalance -= amountPayment
// allways return a positiv number of the remaining balance
// using the absolute amount
remainingBalance = Math.abs(remainingBalance)
// create a new object with the data
let paymentObj = {
month,
monthlyPayment,
interest,
amountPayment,
totalInterest,
remainingBalance,
}
// add the new object in the array
resultsArray.push(paymentObj)
}
return resultsArray
}
// displaying the card information
function displayCard(payments) {
// format number to US dollar
let USDollar = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
})
let monthlyPayment = USDollar.format(payments.payment)
let amount = USDollar.format(payments.amount)
let interest = USDollar.format(payments.interestRate)
let totalCost = USDollar.format(payments.cost)
// add the value to the card
document.getElementById('monthly-payment').textContent = monthlyPayment
document.getElementById('principal').textContent = amount
document.getElementById('interest').textContent = interest
document.getElementById('cost').textContent = totalCost
}
// display the payment details per month
function displayTable(results) {
// format number to US dollar
let USDollar = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
})
// clean up the screen
document.getElementById('tblResult').innerHTML = ''
// get a copy of the template
let template = document.getElementById('table-template')
// getting the div id "tblResult"
let tableData = document.getElementById('tblResult')
// the arrow function that return the template
results.forEach((newItem) => {
let templateCopy = template.content.cloneNode(true)
templateCopy.querySelector('.month').textContent = newItem.month
templateCopy.querySelector('.payment').textContent = USDollar.format(
newItem.monthlyPayment
)
templateCopy.querySelector('.principal').textContent = USDollar.format(
newItem.amountPayment
)
templateCopy.querySelector('.interest').textContent = USDollar.format(
newItem.interest
)
templateCopy.querySelector('.totalInterest').textContent =
USDollar.format(newItem.totalInterest)
templateCopy.querySelector('.balance').textContent = USDollar.format(
newItem.remainingBalance
)
tableData.appendChild(templateCopy)
})
}
Time to desistify the code!
Before starting to code it is always essential to understand the problem that we have to solve, and for this challenge I had this small list of tasks to accomplish:
- Get the values from the user.
- Calculate the interest rate base on it's value.
- Calculate the montly payment and store the value inside and object.
- Calculate the total monthly payment.
- Display the result of the total payment in a card.
- Display the detail of the result in a table for each month.
getValues()
The getValues
function takes care of
retrieving the values provided by the user of our
application, knowing that the values retrieved will be
of type string we must convert them into numeric values.
And finally we use the SweetAlert2 helper to validate
the data and finally call the
totalPayment
function to pass the values
recovered after their conversion and the
displayCard
function to display the result
into the montly payment card. Use the
totalMonthlyPayment
function which contains
an array of objects with all the monthly details. And
finally using a displayTable
function to
display the monthly result in a table.
interestRates()
I could still working without the
interestRates
function, and instead use the
following formula: (rate / 1200)
, but as I
don't really like using hard coded values, so I created
this little function in order to use it in place of this
formula. At the end, all this function does is returning
the interest in question, whatever its value.
totalPayment()
The totalPayment
function receives three
parameters: the loan amount (the
principal
), the interest percentage,
and the total months (the term
) it
will take to repay the debt. The following formula will
allow us to calculate the monthly payment, I didn't
invent it, it's finance:
(amount loaned) * (rate / 1200) / (1 - (1 +
rate/1200) ^(-Number of Months)).
So to continue, I calculate the total cost, and the
total interest. Then store all that in an object and
then return the object for later use. As simple as that!
totalMonthlyPayment()
The totalMonthlyPayment
function supports
creating monthly data and returning it. For this you
will need parameters to pass when calling the function,
and in our case we need the amount borrowed (the
principal), the interest rate, the duration of the loan,
and the amount to be paid monthly. So we start by
creating an empty array, and we know that before the
first month of payment the remaining balance is the
principal, and the interest rate is equal to 0.
The for loop iterates over each month from
month 1 to the value of the variable
term
. Inside the loop, we calculates the
interest to be paid for the current month using the
formula:
interest = remainingBalance *
interestRates(rate)
.
See the interestRates function that we've
create above to returns the interest rate.
Next, we calculate the amount to be paid for the current
month by subtracting the interest from the monthly
payment:
amountPayment = monthlyPayment - interest
.
After that we update the total of interest, and update
the remaining balance for the next iteration by
subtracting the amount paid from the remaining balance:
remainingBalance -= amountPayment
, than we
ensure that the remaining balance is always positive by
taking the absolute value using
Math.abs(remainingBalance)
.
Now we need to capture all those data, and on of the
best way to do this is by creating a new object to store
them all. That's why we create the new object
paymentObj
that holds the details for the
data we need to store such as, the month number, monthly
payment, interest, amount payment (principal), total
interest, and remaining balance. Right after that we
just need to add each newly created payment object
inside an array called resultsArray
. After
executing our for loop all we have to do is returning
our collection, or our array of objects.
displayCard()
The displayCard
function is meant to take
payment information, format it as US dollars, and update
specific HTML elements on a webpage with the formatted
values. Formatting Numbers as USD: The function
uses the Intl.NumberFormat
constructor to
create a formatter for US dollars. It sets the style to
'currency' and the currency to 'USD'. This formatter
(USDollar) is then used to format various numeric
values such as the amount
,
interestRate
, and
cost
properties of the payments. Then we
accesses specific HTML elements using
document.getElementById
and updates their content with the formatted values.
displayTable()
The displayTable
function takes an array of
results, formats numeric values as US dollars, creates a
table row for each result based on a template, populates
the table row with data, and appends it to a table on
the web page.
Similar to the previous function, we create a formatter
for US dollars using the
Intl.NumberFormat
constructor. Than we
clear the content of the HTML element with the ID
'tblResult
' to ensure that the table starts
with a clean slate before adding new data when we click
the button. Next, we access the template for the table
from an HTML element with the ID
'table-template
'. This template is a
non-displayed template in the HTML document (Read more
about template tag in my project:
Step-On-No-Pets). Now it's time to create a new template or clone the
template, so inside the loop we create a deep copy of
the template including it's content. After that we need
to populates various elements within the cloned template
with data from the current newItem in the loop. At the
end, all we have to do is to append the template to the
table, so the cloned and populated template is appended
to the HTML element that contains the ID
'tblResult
'.