First time here, first time writing about JavaScript, first time writing an article in English… Definitely this is the article of the first times in everything.
A few days ago, reading Josh Comeau's fantastic article «How To Learn Stuff Quickly», I discovered the «Learn in Public» method to help me to learn and understand all new concepts that I'm trying to add to my professional career. Part of this method, or an application example, is precisely to write about the new concepts that you are learning to help you to learn them, understand them and incorporate them into your skills. But… without further ado, let's get started.
As part of my training in JavaScript, I have been doing quite a few exercises. There are many websites dedicated to that. One of them is «frontendeval». For this tutorial, I have chosen the "Mortgage Calculator" exercise.
For me, the biggest difficulty was not in the JavaScript logic but in understanding how the mathematical formula that performs the calculation works, this is it:
P(r(1+r)^n/((1+r)^n)-1))
I spent days trying to figure it out; calculus was never my thing. But luckily, the Internet was always there to help, and this video "How to Calculate a Mortgage Payment" clarified all the concepts for me.
I now had the necessary tools to start developing my Mortgage Calculator, so let's start coding.
We'll need a piece of HTML for our mortgage form:
<main class="mortgage-form-wrapper">
<header>
<h1>Mortgage calculator 🧮</h1>
</header>
<form id="mortgage-form" action="" class="mortgage-form">
<div class="mortgage-form--row">
<label for="amount-input">Principal loan amount</label>
<input type="number" name="amount-input" id="amount-input" min="50000" placeholder="Min 50000" required>
<p class="mortgage-form--help">Min 50000</p>
</div>
<div class="mortgage-form--row">
<label for="interest-rate-input">Interest rate</label>
<input type="number" name="amount-input" id="interest-rate-input" min="1" max="20" placeholder="Min 1% max 20%" required>
<p class="mortgage-form--help">Min 1% max 20%, without '%' symbol</p>
</div>
<div class="mortgage-form--row">
<label for="length-of-loan-input">Length of loan</label>
<input type="number" name="amount-input" id="length-of-loan-input" min="1" max="40" placeholder="Min 1 year, max 40 years" required>
<p class="mortgage-form--help">Min 1 year, max 40 years</p>
</div>
<div class="mortgage-form--row mortgage-form--row__button-wrapper">
<button type="button" id="calculate-btn">Calculate</button>
<button type="reset" id="reset-btn" class="reset-btn">Reset</button>
</div>
</form>
<p class="motgage-result"><span id="mortgage-final-result"></span></p>
</main>
And maybe a bit of CSS (SCSS):
@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap');
* { box-sizing: border-box; }
::placeholder {
font-size: small;
color: #aaa
}
html, body {
margin: 0;
padding: 0;
}
body {
font-family: 'Lato', sans-serif;
display: flex;
flex-direction: column;
height: 100vh;
align-items: center;
justify-content: center;
background: transparent url('../img/background.jpg') center center no-repeat;
background-size: cover;
padding: 0 15px;
}
a {
text-decoration: none;
transition: all .3s ease;
&:hover, &:focus { text-decoration: underline; }
}
.photo-credit {
position: absolute;
bottom: 15px;
right: 15px;
font-size: .725rem;
a {
color: white;
opacity: .5;
&:hover, &:focus { opacity: 1; }
}
}
.mortgage-form-wrapper {
background-color: white;
padding: 30px 30px 0;
box-shadow: 0 0 5px rgba(black,.25);
min-width: 420px;
@media screen and (max-width: 480px) {
min-width: 0;
width: 100%;
}
h1 { margin: 0 0 15px; }
input {
transition: all .5s ease;
&[type="number"] {
border: 1px solid #ddd;
border-radius: 5px;
width: 100%;
font-size: small;
padding: 11px;
&:invalid {
background-color: rgba(lightcoral,.075);
border: 1px solid lightcoral;
outline: none;
}
&:empty {
background-color: white;
border: 1px solid #ddd;
}
&:valid {
background-color: rgba(lightseagreen,.075);
border: 1px solid lightseagreen;
outline: none;
}
&.error {
background-color: rgba(lightcoral,.075);
border: 1px solid lightcoral;
outline: none;
&:valid {
background-color: rgba(lightseagreen,.075);
border: 1px solid lightseagreen;
outline: none;
}
}
}
}
p { margin: 0 0 15px; }
label { display: block; }
}
p.motgage-result {
margin: 0 0 15px;
.error-message {
color: lightcoral;
font-weight: 700;
}
.success-message {
color: lightseagreen;
font-weight: 700;
}
}
.mortgage-form--help {
font-size: small;
font-style: italic;
color: #a9a9a9;
text-align: right;
}
.mortgage-form--row__button-wrapper {
text-align: center;
margin-bottom: 30px;
display: flex;
justify-content: center;
button {
border: none;
background-color: lightcoral;
padding: 12px 20px;
color: white;
font-weight: 700;
text-transform: uppercase;
cursor: pointer;
transition: all 0.3s ease;
outline: 2px solid lightcoral;
margin: 0 7.5px;
&:hover, &:focus {
background-color: #666;
outline: 2px solid #666;
}
&.form-success,
&.disabled {
background-color: #a9a9a9;
outline: 2px solid #a9a9a9;
cursor: not-allowed;
&:hover, &:focus {
background-color: #a9a9a9;
outline: 2px solid #a9a9a9;
}
}
}
}
.reset-btn { display: none; }
I used this image for background, feel free to use whichever you want. At this point, your mortgage form should look something like this:
First, we are going to store our form inputs into JavaScript variables:
// The principal loan amount
const amountInput = document.getElementById('amount-input')
// The interest rate of our loan
const interestRateInput = document.getElementById('interest-rate-input')
// The length of our loan
const lengthOfLoanInput = document.getElementById('length-of-loan-input')
Next, create a function for the calculation.
function calculateMortgagePayment() {}
Inside the function, we collect the values that the user writes in the inputs using ".value".
const borrowedMoney = amountInput.value
const lengthOfLoan = lengthOfLoanInput.value * 12
const interestRate = interestRateInput.value
const calculedInterest = interestRate / 100
const interestReady = calculedInterest / 12
Also within the function, we begin to apply the formula to calculate our monthly bill.
const percentage = interestReady
const percentagePlusOne = interestReady + 1
const exponentiationOperator = (percentagePlusOne ** lengthOfLoan)
const firstDividend = percentage * exponentiationOperator
const secondDividend = exponentiationOperator - 1
const division = firstDividend / secondDividend
const mortgage = borrowedMoney
const quotas = mortgage * division
And to complete our function, we show the results of the calculations.
mortgageFinalResult.textContent = successMessage + quotas.toFixed(2)
mortgageFinalResult.classList.add('success-message')
calculateBtn.classList.add('form-success')
calculateBtn.setAttribute('disabled','disabled')
resetBtn.style.display = 'block'
And… Voilà! Now, our mortgage calculation function should look like this.
function calculateMortgagePayment() {
// We take initial values
const borrowedMoney = amountInput.value
const lengthOfLoan = lengthOfLoanInput.value * 12
const interestRate = interestRateInput.value
const calculedInterest = interestRate / 100
const interestReady = calculedInterest / 12
// We start the calculations
const percentage = interestReady
const percentagePlusOne = interestReady + 1
const exponentiationOperator = (percentagePlusOne ** lengthOfLoan)
const firstDividend = percentage * exponentiationOperator
const secondDividend = exponentiationOperator - 1
const division = firstDividend / secondDividend
const mortgage = borrowedMoney
const quotas = mortgage * division
// And we show the results
mortgageFinalResult.textContent = successMessage + quotas.toFixed(2)
mortgageFinalResult.classList.add('success-message')
calculateBtn.classList.add('form-success')
calculateBtn.setAttribute('disabled','disabled')
resetBtn.style.display = 'block'
}
Once our function is ready, we prepare two constants, one for error and another one for success messages.
const errorMessage = 'There is an error in the form, please check it! 😥'
const successMessage = '🧮 Your monthly mortgage payment will be: '
I add some quick validation for our mortgage form. You can find more information about this, for example, in MDN Web Docs by Mozilla.
amountInput.addEventListener('focusout',function(e){
if (!amountInput.validity.valid) {
amountInput.classList.add('error')
} else {
amountInput.classList.remove('error');
}
})
interestRateInput.addEventListener('focusout',function(e){
if (!interestRateInput.validity.valid) {
interestRateInput.classList.add('error')
} else {
interestRateInput.classList.remove('error');
}
})
lengthOfLoanInput.addEventListener('focusout',function(e){
if (!lengthOfLoanInput.validity.valid) {
lengthOfLoanInput.classList.add('error')
} else {
lengthOfLoanInput.classList.remove('error');
}
})
And the last step; an online form without buttons is not a form, don't you think? First a button for launching our function.
calculateBtn.addEventListener('click', function(e){
if (amountInput.validity.valid && interestRateInput.validity.valid && lengthOfLoanInput.validity.valid) {
calculateMortgagePayment()
} else {
mortgageFinalResult.textContent = errorMessage
mortgageFinalResult.classList.add('error-message')
calculateBtn.classList.add('form-error')
if (!amountInput.validity.valid) {
amountInput.classList.add('error')
}
if (!interestRateInput.validity.valid) {
interestRateInput.classList.add('error')
}
if (!lengthOfLoanInput.validity.valid) {
lengthOfLoanInput.classList.add('error')
}
}
})
And the last one, another button to reset our form.
resetBtn.addEventListener('click', function() {
resetBtn.style.display = 'none'
mortgageFinalResult.textContent = ''
calculateBtn.removeAttribute('disabled')
calculateBtn.classList.remove('form-success')
})
There we go! You can find all the lines of code in my repository on GitHub. Or test directly the mortgage calculator.
Sure there are best ways to get the same result, I know. I am just trying to share what I have learnt and, along the way, reinforce my own knowledge. If you know of a better way and want to share it here, I will be happy to read it in the comments.
Cheers! ♥️
Top comments (5)
Hey Enrique! Thank you so much for this incredible insight. It is exactly what I've been looking for for the last couple of weeks. I started getting familiar with JavaScript a couple of weeks ago, and posts like this are priceless for my learning process. I'm also currently thinking about moving into a bigger apartment, so I'm quite interested in getting a mortgage. I was rather skeptical about it, but I luckily bumped into Mortgage Advice Bristol, whose staff members did their absolute best to answer all of my questions and find the right solution for my particular case. Cheers!
Hey Herefer! 👋🏼
I am very glad that it can be useful to you. I've been working as a frontend for many years, but JavaScript has always been my weak point. Furthermore, I'll continue to post simple exercises like this one, for people like you and me, who need to improve or incorporate JavaScript into their professional skills.
Thanks again for your kind words. 😊
Hi, dear i am a full stack php and javascript developer having build 1000s plus tools in javascript i do like to work on your calculator if interested let me know
Hi 👋🏼
The code is completely opened 😊 Feel free to use any part or all of it.
I am working on a website that is related to mortgage. Will you make a toll to calculate Industrial Property Loan? I will embed it with my website.