Mortgage loan calculator with JavaScript
Tags: javascript, beginners, programming, tutorial
Published: 2022-02-23 09:56:52

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](https://www.joshwcomeau.com/blog/how-to-learn-stuff-quickly/)», I discovered the «[Learn in Public](https://www.swyx.io/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](https://frontendeval.com/)». For this tutorial, I have chosen the "[Mortgage Calculator](https://frontendeval.com/questions/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.

{% youtube Pgot9V7uZXw %}

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:

```html
<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)**:

```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](https://unsplash.com/photos/JXI2Ap8dTNc), feel free to use whichever you want. At this point, your mortgage form should look something like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aiwsuq3ak0resbsa7huy.png)

First, we are going to store our form inputs into JavaScript variables:

```javascript
// 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.

```javascript
function calculateMortgagePayment() {}
```

Inside the function, we collect the values that the user writes in the inputs using ".value".

```javascript
  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](https://en.wikipedia.org/wiki/Mortgage_calculator#Monthly_payment_formula).

```javascript
  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.

```javascript
  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.

```javascript
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.

```javascript
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](https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation).

```javascript
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.

```javascript
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.

```javascript
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](https://github.com/bosspetta/JavaScript-Mortgage-Calculator). Or [test directly the mortgage calculator](https://bosspetta.github.io/JavaScript-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! ♥️