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'.

That's kind of cool, right? 😎