Edit in JSFiddle

var myApp = angular.module('RealEstateApp', []);

Date.prototype.yyyymmdd = function() {         
    
    var yyyy = this.getFullYear().toString();                                    
    var mm = (this.getMonth()+1).toString(); // getMonth() is zero-based         
    var dd  = this.getDate().toString();             
    
    return yyyy + '-' + (mm[1]?mm:"0"+mm[0]) + '-' + (dd[1]?dd:"0"+dd[0]);
};  


myApp.directive("percent", function($filter){
    var p = function(viewValue){
        var m = viewValue.match(/^(\d+)\/(\d+)/);
        if (m != null)
          return $filter('number')(parseInt(m[1])/parseInt(m[2]), 4);
        return $filter('number')(parseFloat(viewValue)/100, 4);
    };

    var f = function(modelValue){
        return $filter('number')(parseFloat(modelValue)*100, 2);
    };
    
    return {
        require: 'ngModel',
        link: function(scope, ele, attr, ctrl){
            ctrl.$parsers.unshift(p);
            ctrl.$formatters.unshift(f);
        }
    };
});

myApp.controller('RealEstateController',['$scope', function($scope) {
 // ------- MODELS --------
    
    // Month number, amortization date, interest, principal, principal balance
    $scope.Amortizations = [];
        
    $scope.TotalContractPrice = 4000000;
    $scope.DownPaymentPercent = .2; 
    $scope.DownPayment = 0;
    $scope.InstallmentPrincipal = 0;
    
    $scope.TotalInterest = 0;
    $scope.TotalPrincipal = 0;
    $scope.TotalAmortization = 0;
    
    
    
    $scope.NumberOfYearsToPay = 5;
    $scope.NumberOfMonthsToPay = 0;
    $scope.PaymentModeInMonths = 1; // monthly
    


    $scope.InterestRatePerAnnum = 0.21;
    $scope.PeriodicInterestRate = 0;
    $scope.AmortizationFactor = 0;
    $scope.AmortizationAmount = 0;
    $scope.AmortizationStartDate = new Date('Feb 28, 2013');
    $scope.AmortizationStartDateText = $scope.AmortizationStartDate.yyyymmdd();
    
    // determine payment terms based on budget
    $scope.DeterminePaymentTerms = false; 
    $scope.Budget = 0;
    
    
    $scope.AdvancedPayments = [
        { MonthNumber: null, Payment: null }
    ];
    
    
    // ------- CONTROLLER's ACTIONS -----------
    
    $scope.ComputeYears = function() {
        $scope.NumberOfYearsToPay = $scope.NumberOfMonthsToPay / 12;
    }
    
    $scope.ComputeFromTotalContractPrice = function() {
        $scope.ComputeDownPayment();
        $scope.ComputeInstallmentPrincipal();
        $scope.ComputeAmortizationFactor();
    }
    
    
    $scope.ComputeFromYears = function() {
        $scope.NumberOfMonthsToPay = $scope.NumberOfYearsToPay * 12;
        
        $scope.ComputeAmortizationFactor();
    };
    
    $scope.ComputeFromMonths = function() {
         $scope.ComputeYears();
         
         $scope.ComputeAmortizationFactor();
    };
    
    $scope.ComputeFromPaymentModeInMonths = function() {
        $scope.ComputeAmortizationFactor();        
    };
    
    
    
    $scope.ComputeDownPaymentPercent = function() {
        $scope.DownPaymentPercent = $scope.DownPayment / $scope.TotalContractPrice;                        
    };
    
    $scope.ComputeInstallmentPrincipal = function() {        
        $scope.InstallmentPrincipal = $scope.TotalContractPrice - $scope.DownPayment;
    };    
        
    
    $scope.ComputeFromDownPayment = function() {
        $scope.ComputeDownPaymentPercent();
        $scope.ComputeInstallmentPrincipal();
        
        
        if ($scope.DeterminePaymentTerms) {
            $scope.ComputeFromAmortizationAmount();
        }
        else {        
            $scope.ComputeAmortizationFactor();
        }
    };
    
    
    $scope.ComputeDownPayment = function() {
        $scope.DownPayment = $scope.DownPaymentPercent * $scope.TotalContractPrice;        
    }
    
    $scope.ComputeFromDownPaymentPercent = function() {
        $scope.ComputeDownPayment();
        $scope.ComputeInstallmentPrincipal();
        
        $scope.ComputeAmortizationFactor();
    };
    

    
    $scope.ComputeFromInstallmentPrincipal = function() {
        $scope.DownPayment = $scope.TotalContractPrice - $scope.InstallmentPrincipal;
        $scope.ComputeDownPaymentPercent();
        
        
        $scope.ComputeAmortizationFactor();        
    };
    
    
    $scope.ComputeAmortizationFactor = function() {
        
        $scope.AmortizationStartDate = new Date($scope.AmortizationStartDateText);
        
        var pir = $scope.PeriodicInterestRate = $scope.InterestRatePerAnnum / (12 / $scope.PaymentModeInMonths);
        
        
        if ($scope.PaymentModeInMonths == 0) {
            $scope.AmortizationFactor = 0;
            return;
        }
            
        
        
        var compoundTerms = $scope.NumberOfMonthsToPay / $scope.PaymentModeInMonths;
        
        var amortizationFactor = 0;
        
        if (compoundTerms == 0) {
            $scope.AmortizationFactor = 0;
            return;
        }
        
        if ($scope.NumberOfMonthsToPay > 0) {
            if ($scope.InterestRatePerAnnum > 0) {
                $scope.AmortizationFactor = pir / (1 - (1 / Math.pow( 1 + pir, compoundTerms ) ) ); 
            }
            // 0% interest
            else {
                $scope.AmortizationFactor = 1 / compoundTerms;
            }
        }
        else {
            // nothing, this is handled by compoundTerms == 0
        }
        
        $scope.AmortizationFactor = $scope.round( $scope.AmortizationFactor, 10);
        
        if ($scope.DeterminePaymentTerms) {
            // AmortizationAmount is based on Budget
        }
        else {
            $scope.AmortizationAmount = $scope.AmortizationFactor * $scope.InstallmentPrincipal;
        }
        
        $scope.CreateAmortizationSchedule();
    };
    
    
    $scope.ComputeFromInterestRatePerAnnum = function() {
        $scope.ComputeAmortizationFactor();
    };
    
    
    $scope.FirstInterest = function() {
        return Math.ceil($scope.PeriodicInterestRate * $scope.InstallmentPrincipal);
    };
    
    $scope.IsBudgetLessThanTheFirstInterest = function() {
        return $scope.Budget <= $scope.FirstInterest();
    };
    
    
    $scope.ComputeFromAmortizationAmount = function() {
    
        // http://oakroadsystems.com/math/loan.htm#LoanNumber        
        // N = −log(1−iA/P) / log(1+i)
        
        
        var interest = $scope.FirstInterest();
                
        if ($scope.Budget <= interest) {
            return;
        }
        
        
        
        var n = (-Math.log(1 - $scope.PeriodicInterestRate * $scope.InstallmentPrincipal / $scope.Budget)) 
                / Math.log(1 + $scope.PeriodicInterestRate);
            
        
            
        if (!isNaN(n) && n > 0) {        
            $scope.AmortizationAmount = $scope.Budget;
            $scope.NumberOfMonthsToPay = Math.ceil(n);        
            $scope.ComputeYears();
            $scope.CreateAmortizationSchedule();            
        }
        
    };
    
    
    $scope.EvaluatePaymentTerms = function() {
        // based on budget
        if ($scope.DeterminePaymentTerms == true) {
            $scope.Budget = 0;
            $scope.ComputeFromAmortizationAmount();
        }
        else {
            $scope.ComputeFromInstallmentPrincipal();
        }
    };
    
    
    $scope.AddAdvancedPayment = function() {
        $scope.AdvancedPayments.push({MonthNumber: null, Payment: null});
    };
    
    $scope.RemoveAdvancedPayment = function(index) {
        $scope.AdvancedPayments.splice(index,1);
        $scope.CreateAmortizationSchedule();
    };
    
    $scope.CreateAmortizationSchedule = function() {
        
        var amort = $scope.Amortizations = [];
        
        
        var pir = $scope.PeriodicInterestRate;        
        var ma = $scope.AmortizationAmount;
        
        var prevBalance = $scope.InstallmentPrincipal;

        amort.push({
                MonthNumber : 0, 
                AmortizationDate : null,
                Interest : null, 
                Principal : null, 
                Amortization : null, 
                AdvancedPayment : null,
                PrincipalBalance : prevBalance});
        

        
        var i = 0;
        while (Math.floor(prevBalance) > 0) {
            var interest = pir * prevBalance;
            var principal = ma - interest;
            
            if (principal > prevBalance) {
                principal = prevBalance;
            }
            
            
            var amortization = interest + principal;
            var advancedPayment = 0;
            
            var advancedPaymentFilter = $scope.AdvancedPayments.filter(function(pay) {                 
                return pay.MonthNumber-1 == i;
            });
            
            if (advancedPaymentFilter.length == 1) {
                advancedPayment = advancedPaymentFilter[0].Payment;
            }
            
            prevBalance = prevBalance - principal - advancedPayment;
            
            
            var startDate = $scope.AmortizationStartDate;
            var nthMonthFromStartDate = new Date(new Date(startDate).setMonth(startDate.getMonth()+i));
                        
            i += parseInt($scope.PaymentModeInMonths);
            amort.push({
                MonthNumber : i, 
                AmortizationDate : nthMonthFromStartDate,
                Interest : interest, 
                Principal : principal, 
                Amortization : amortization, 
                AdvancedPayment : advancedPayment,
                PrincipalBalance : prevBalance});
        }
        
        
        $scope.TotalInterest = 
            amort
            .map(function(a) { return a.Interest; })
            .reduce(function(prev,current) { return prev + current; });
            
        $scope.TotalPrincipal = 
            amort
            .map(function(a) { return a.Principal; })
            .reduce(function(prev,current) { return prev + current; });
            
        $scope.TotalAmortization = 
            amort
            .map(function(a) { return a.Amortization })
            .reduce(function(prev,current) { return prev + current; });
    };
    
    $scope.round = function(number,X) {
        // rounds number to X decimal places, defaults to 2
        X = (!X ? 2 : X);
        return Math.round(number*Math.pow(10,X))/Math.pow(10,X);
    }
    
            
    $scope.ComputeFromDownPaymentPercent();
    $scope.ComputeFromYears();
    $scope.ComputeAmortizationFactor();    
    
}]);
<body ng-controller="RealEstateController" ng-app="RealEstateApp">


    <div style='float: left' class='input'>
    <fieldset>
        <legend>Selling</legend>
        
        <div><label for='TotalContractPrice'>Total Contract Price</label></div>
        <div>
        <input 
        id='TotalContractPrice' 
        ng-model='TotalContractPrice' 
        ng-change='ComputeFromTotalContractPrice()'
        ng-disabled='DeterminePaymentTerms'/>
        </div>

        <div><label for='DownPaymentPercent'>Downpayment %</label></div>
        <div><input 
        id='DownpaymentPercent' ng-model='DownPaymentPercent' ng-change='ComputeFromDownPaymentPercent()' 
        ng-disabled='DeterminePaymentTerms'
        percent/></div>
        
        <div><label for='DownPayment'>Downpayment</label></div>
        <div><input id='DownPayment' ng-model='DownPayment' ng-change='ComputeFromDownPayment()' ng-disabled='DeterminePaymentTerms' type='number'/></div>
        
        <div><label for='InstallmentPrincipal'>Installment Principal</label></div>
        <div><input id='InstallmentPrincipal' ng-model='InstallmentPrincipal' ng-change='ComputeFromInstallmentPrincipal()' ng-disabled='DeterminePaymentTerms'/></div>
        
    </fieldset>



    <fieldset>

        <legend>Payment Terms</legend>
    
        <div><label for='NumberOfYearsToPay'>Number of years to pay</label></div>
        <div><input ng-disabled='DeterminePaymentTerms' id='NumberOfYearsToPay' ng-model='NumberOfYearsToPay' ng-change='ComputeFromYears()' type='number'/></div>
    
        
        <div><label for='NumberOfMonthsToPay'>Number of months to pay</label></div>
        <div><input ng-disabled='DeterminePaymentTerms' id='NumberOfMonthsToPay' ng-model='NumberOfMonthsToPay' ng-change='ComputeFromMonths()' type='number'/></div>
        
        <div><label for='PaymentModeInMonths'>Payment Mode(1 = Monthly, 3 = Quarterly, ..., 12 = Yearly)</label></div>
        <div><input ng-disabled='DeterminePaymentTerms' id='PaymentModeInMonths' ng-model='PaymentModeInMonths' ng-change='ComputeFromPaymentModeInMonths()' type='number'/></div>
        
        <div><label for='InterestRatePerAnnum'>Interest Rate Per Annum</label></div>
        <div><input ng-disabled='DeterminePaymentTerms' id='InterestRatePerAnnum' ng-model='InterestRatePerAnnum' ng-change='ComputeFromInterestRatePerAnnum()' percent/></div>
        
        
              
    </fieldset>

    
    <fieldset>
        
        <legend>Amortization</legend>


        
        <div><label for='AmortizationFactor'>Amortization Factor</label></div>
        <div><b>{{AmortizationFactor}}</b></div>
        
        
        <div><label for='AmortizationAmount'>Amortization Amount</label></div>
        <div><b>{{AmortizationAmount | number:2}}</b></div>
        
        <div><label for='InterestRatePerAnnum'>Amortization Start Date</label></div>
        <div><input style='width: 300px' ng-disabled='true' id='AmortizationStartDate' ng-model='AmortizationStartDate' ng-change='ComputeFromInterestRatePerAnnum()'/></div>        
        
        <div><input type='date' ng-model='AmortizationStartDateText' ng-change='ComputeFromInterestRatePerAnnum()'/></div>
        
        <hr/>
        <div><input type='checkbox' ng-model='DeterminePaymentTerms' ng-change='EvaluatePaymentTerms()'/>Determine Payment Terms based on your budget</div>
        <div ng-show='DeterminePaymentTerms'>
            <div><input ng-show='DeterminePaymentTerms' id='Budget' ng-model='Budget' ng-change='ComputeFromAmortizationAmount()'/></div>
            <div ng-show='IsBudgetLessThanTheFirstInterest()'>Budget should be more than the first interest({{FirstInterest() | number:2}}). Significantly higher if possible, otherwise you are just wasting your money on the interest ({{InterestRatePerAnnum * 100}}%)</div>
        </div>
            
        
    </fieldset>
    
    
    <fieldset><legend>Totals</legend>
        <div style='float: left; margin-right: 5px'>Total Interest: </div>
        <div><b>{{TotalInterest | number:2}}</b></div>
        
        <div style='float: left; margin-right: 5px'>Total Principal: </div>
        <div><b>{{InstallmentPrincipal | number:2}} (aka Installment Principal)</b></div>        
        
        <div style='float: left; margin-right: 5px'>Total Amortization: </div>
        <div><b>{{TotalAmortization | number:2}}</b></div>        

        <div style='float: left; margin-right: 5px'>Total Amortization + Downpayment: </div>
        <div><b>{{TotalAmortization + DownPayment | number:2}}</b></div>                        
    </fieldset>
    
        
    <fieldset>
        <legend>Extra Payments<button ng-click="AddAdvancedPayment()">+</button></legend>
        <div ng-repeat="adv in AdvancedPayments">
            
            <input ng-model="adv.MonthNumber" placeholder="Month Number" ng-change="CreateAmortizationSchedule()" type='number'>
            <input ng-model="adv.Payment" placeholder="Payment" ng-change="CreateAmortizationSchedule()" type='number'>
                <button ng-click="RemoveAdvancedPayment($index)">-</button>
            
        </div>
    </fieldset>    
        
    </div>
    

    
    <div class='amort' style='float: left'>
    <fieldset>
        <legend>Amortization Schedule</legend>    
        
        <table ng-show='Amortizations.length > 0' class='table'>
            <thead>
                <tr class='header'>
                    <th>Month#</th><th>Date</th><th>Interest</th><th>Principal</th><th>Amortization</th><th>Extra Payment</th><th>Balance</th>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat='a in Amortizations'>
                    <td>{{a.MonthNumber}}</td>
                    <td style='text-align: right'>{{a.AmortizationDate | date:'MMM dd, yyyy'}}</td>
                    <td style='text-align: right'>{{a.Interest | number:2}}</td>                    
                    <td style='text-align: right'>{{a.Principal | number:2}}</td>
                    <td style='text-align: right'>{{a.Amortization | number:2}}</td>                    
                    <td style='text-align: right'>{{a.AdvancedPayment | number:2}}</td>
                    <td style='text-align: right'>{{a.PrincipalBalance | number:2}}</td>
                </tr>
            </tbody>
            <tfooter>
                <tr>
                    <td>Total</td><td></td>
                    <td>{{TotalInterest | number:2}}</td>
                    <td>{{TotalPrincipal | number:2}}</td>
                    <td>{{TotalAmortization | number:2}}</td>
                    <td></td>
                </tr>
            </tfooter>
        </table>    
    </fieldset>
    </div>
        
</body>
fieldset { font-size: 13px; font-family : 'Calibri'}
div.input { width: 380px; }
div.amort { width: auto; }
table, th, td { font-size: 13px; font-family : 'Calibri'; }


input {
    -webkit-border-radius: 8px;
    -moz-border-radius: 8px;
    border-radius: 5px;
}


fieldset {
    -webkit-border-radius: 8px;
    -moz-border-radius: 8px;
    border-radius: 8px;
}

table.table {
    margin: 20px;
    color: 666;
    font-size: 12px;
    -moz-border-radius: 3px;
    -moz-box-shadow: 0 1px 2px #d1d1d1;
    -webkit-border-radius: 3px;
    -webkit-box-shadow: 0 1px 2px #d1d1d1;
    background: #eaebec;
    border: #ccc 1px solid;
    border-radius: 3px;
    box-shadow: 0 1px 2px #d1d1d1;
    font-family: Arial, Helvetica, sans-serif;
    text-shadow: 1px 1px 0px #fff;
}

table.table tr.even td {
    background: #f6f6f6;
    background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#f6f6f6));
    background: -moz-linear-gradient(top, #f8f8f8, #f6f6f6);
}

table.table th {
    padding: 21px 25px 22px 25px;
    border-bottom: 1px solid #e0e0e0; border-top: 1px solid #fafafa;
    background: #ededed;
    background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#ebebeb));
    background: -moz-linear-gradient(top, #ededed, #ebebeb);
}

table.table th:first-child {
    padding-left: 20px;
    text-align: left
}

table.table a:visited {
    color: #999999;
    font-weight: bold;
    text-decoration: none
}

table.table a:active,
table.table a:hover {
    color: #bd5a35;
    text-decoration: underline
}

table.table a:link {
    color: #666;
    font-weight: bold;
    text-decoration: none
}

table.table tr {
    padding-left: 20px;
    text-align: center
}

table.table tr:first-child th:first-child {
    -moz-border-radius-topleft: 3px;
    -webkit-border-top-left-radius: 3px;
    border-top-left-radius: 3px;
}

table.table tr:first-child th:last-child {
    -moz-border-radius-topright: 3px;
    -webkit-border-top-right-radius: 3px;
    border-top-right-radius: 3px;
}

table.table tr:last-child td {    border-bottom: 0 }

table.table tr:last-child td:first-child {
    -moz-border-radius-bottomleft: 3px;
    -webkit-border-bottom-left-radius: 3px;
    border-bottom-left-radius: 3px;
}

table.table tr:last-child td:last-child {
    -moz-border-radius-bottomright: 3px;
    -webkit-border-bottom-right-radius: 3px;
    border-bottom-right-radius: 3px;
}

table.table tr:hover td {
    background: #f2f2f2;
    background: -webkit-gradient(linear, left top, left bottom, from(#f2f2f2), to(#f0f0f0));
    background: -moz-linear-gradient(top, #f2f2f2, #f0f0f0);
}

table.table tr td {
    padding: 18px;
    border-bottom: 1px solid #e0e0e0; border-left: 1px solid #e0e0e0; border-top: 1px solid #ffffff;
    background: #fafafa;
    background: -webkit-gradient(linear, left top, left bottom, from(#fbfbfb), to(#fafafa));
    background: -moz-linear-gradient(top, #fbfbfb, #fafafa);
}

table.table tr td:first-child {
    padding-left: 20px;
    border-left: 0;
    text-align: left
}