PMT

by whelkaholism

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
<table class="hw-mortgage-calculator">
  <tr>
    <td>Cost of dwelling is</td>
    <td><span class="money-field"><input type="text" data-bind="textInput: Cost" /></span></td>
  </tr>
  <tr>
    <td>I have a deposit of</td>
    <td><span class="money-field"><input type="text" data-bind="textInput: Deposit" /></span></td>
  </tr>
  <tr>
    <td>Balance to pay off is</td>
    <td><span class="money-field"><input type="text" readonly data-bind="textInput: Balance" /></span></td>
  </tr>
  <tr class="sep">
    <td colspan="2">
      <div></div>
    </td>
  </tr>
  <tr>
    <td>Annual interest rate</td>
    <td>
      <div>
        <input class="sm" type="text" data-bind="textInput: APR" />
        <span>%</span>
      </div>
    </td>
  </tr>
  <tr>
    <td>Repayment term</td>
    <td>
      <div>
        <input class="sm" type="text" data-bind="textInput: Term" />
        <span>years</span>
      </div>
    </td>
  </tr>
  <tr class="sep">
    <td colspan="2">
      <div></div>
    </td>
  </tr>
  <tr>
    <td>Your monthly payment will be</td>
    <td><span class="money-field"><input type="text" readonly data-bind="textInput: MonthlyPayment" /></span></td>
  </tr>
  <tr class="sep">
    <td colspan="2">
      <div></div>
    </td>
  </tr>
  <tr>
    <td>Your monthly take home income</td>
    <td><span class="money-field"><input type="text" data-bind="textInput: MonthlyTakeHome" /></span></td>
  </tr>
  <tr>
    <td>35% Heartward payment</td>
    <td><span class="money-field"><input type="text" readonly data-bind="textInput: HeartwardPayment" /></span></td>
  </tr>
</table>

CSS

body { background: #202020 }

.hw-mortgage-calculator {
  background: rgba(255, 255, 255, 0.85);
  border-radius: 5px;
}

.hw-mortgage-calculator td {
  font-size: 1rem;
  padding: 0.25rem 0.75rem;
}

.hw-mortgage-calculator input[type=text] {
  padding: 0.35rem 0.75rem;
  font-size: 1rem;
  font-weight: 600;
  width: 8rem;
  border: 1px solid #be4488;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.75);
}

.hw-mortgage-calculator .money-field input[type=text] {
  padding: 0;
  border: none;
  background: transparent;  
  width: 8rem;
}

.hw-mortgage-calculator .money-field {
  display: inline-flex;
  align-items: center;
  padding: 0.35rem 0.75rem;
  width: 8rem;
  border: 1px solid #be4488;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.75);
}

.hw-mortgage-calculator .money-field:before {
  content: '£';
  padding-right: 0.25rem;
  font-weight: 900;
}

.hw-mortgage-calculator input[readonly] {
  border-style: dotted;
  outline: none;
}

.hw-mortgage-calculator input[type=text].sm {
  width: 4rem;
}

.hw-mortgage-calculator tr.sep div {
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid #be4488;
}

JavaScript

function Model()
{
	var _this = this; 
  
	this.Cost = ko.observable(250000);
  this.Deposit = ko.observable(100000);
  
  this.APR = ko.observable(6.04);
  this.Term = ko.observable(40);
  this.MonthlyTakeHome = ko.observable(1800);
    
  this.Balance = ko.pureComputed(function() 
  { 
  	return _this.Cost() - _this.Deposit(); 
  });
  
  this.NumPayments = ko.pureComputed(function() {
  	return _this.Term() * 12;
  });
  
  this.MonthlyPayment = ko.pureComputed(function() {
  	return (-PMT(_this.APR() / 100 / 12, _this.NumPayments(), _this.Balance(), 0)).toFixed(2);
  });
  
  this.HeartwardPayment = ko.pureComputed(function() {
  	return (_this.MonthlyTakeHome() * 0.35).toFixed(2);
  });  

var PMT = function(ir, np, pv, fv, type) {
    /*
     * ir   - interest rate per month
     * np   - number of periods (months)
     * pv   - present value
     * fv   - future value
     * type - when the payments are due:
     *        0: end of the period, e.g. end of month (default)
     *        1: beginning of period
     */
    var pmt, pvif;

    fv || (fv = 0);
    type || (type = 0);

    if (ir === 0)
        return -(pv + fv)/np;

    pvif = Math.pow(1 + ir, np);
    pmt = - ir * (pv * pvif + fv) / (pvif - 1);

    if (type === 1)
        pmt /= (1 + ir);

    return pmt;
}
}
var o = new Model();
ko.applyBindings(o);