javascriptangularjsangularjs-ng-change

Updating AngularJS model with ng-change causes one field to become null when updating


Updating AngularJS model values simultaneously on 3 separate fields causes one field to become null on ng-change.

I'm getting some strange behavior with ng-change. What I have is 3 separate fields that all integrate together. One is for a base loan amount, one is for an estimated value of a property and the last one is the loan to value ratio. When entering a value for base loan amount and for estimated value the loan to value ratio is calculated. Then if the user decides to change the loan to value ratio the base loan amount and/or estimated value is recalculated and so on.

The logic that I have so far works as expected. I enter a base loan amount, then enter an estimated value and then the loan to value ratio is calculated. However, as soon as the value is calculated the base loan amount field then empties and becomes null.

I'm not sure why this is happening and I've tried both ng-blur and ng-change and I get the same result. I've debugged this in Chrome for what seems like hours.

I've provided the html that I'm using and the logic for the operation in my controller.

Thank you

Here is Plunker with my code

HTML Content

<div class="form-content">
    <form name="priceSearch" novalidate>
        <!-- Row 1 -->
        <div class="form-row">
            <!-- The LTV (Loan-To-Value) ratio is calculated as the amount of the mortgage lien divided by the appraised value of the property, expressed as a percentage. -->
            <div class="form-group col-md-3">
                <!--if user enters loan amount, update LTV-->
                <label for="baseLoanAmt">Base Loan Amount</label>
                <input name="baseLoanAmt" class="form-control form-control-sm" type="number" placeholder="0.00" ng-step="any" ng-model="pricer.baseLoanAmount" ng-required="true" aria-describedby="blaHelpInline" ng-change="updateBaseLoanAmtEstValLTV('baseLoanAmt', pricer.baseLoanAmount)" ng-model-options="{debounce: {default: 400, blur: 0}}">
            </div>
            <div class="form-group col-md-3">
                <label for="estimatedVal">Estimated Value</label>
                <input name="estimatedVal" class="form-control form-control-sm" type="number" placeholder="0.00" step="any" ng-model="pricer.appraisedEstimatedValue" ng-required="true" aria-describedby="estValHelpInline" ng-change="updateBaseLoanAmtEstValLTV('estimatedVal', pricer.appraisedEstimatedValue)" ng-model-options="{debounce: {default: 400, blur: 0}}">
            </div>
            <div class="form-group col-md-3">
                <!--if user enters LTV, update base loan amount-->
                <label for="ltvRatio">LTV</label>
                <input name="ltvRatio" class="form-control form-control-sm" type="number" ng-step="any" ng-model="pricer.ltvRatio" ng-change="updateBaseLoanAmtEstValLTV('ltvRatio', pricer.ltvRatio)" ng-model-options="{debounce: {default: 400, blur: 0}}" ng-pattern="/^\d+(\.\d{1,2})?$/">
            </div>
            <div class="form-group col-md-3">
                <label>Loan Purpose</label>
                <select class="form-control form-control-sm" ng-model="pricer.loanInformation.loanPurpose" ng-options="obj.val as obj.key for obj in loanPurposeOptions" ng-required="true">
                </select>
            </div>
        </div>
        <!-- End Row 1 -->
    </form>
</div>

Controller Logic

app.controller('pricingSearch', ["$scope", "$rootScope", "$q", "dal", "$http", "$timeout", "$filter", function ($scope, $root, $q, _dal, $http, $timeout, $filter) {

    // Precision Round function
    function precisionRound(number, precision) {
        var factor = Math.pow(10, precision);
        return Math.round(number * factor) / factor;
    }

    $scope.pricer = {
        "baseLoanAmount": 0,
        "appraisedEstimatedValue": 0,
        "ltvRatio": 0,
        "fico": 700,
        "debtToIncomeRatio": 15.0,
        "waiveEscrows": false,
        "loanType": "Conforming",
        "loanTerms": {
            "ThirtyYear": true
        }
    };

    $scope.updateBaseLoanAmtEstValLTV = function (fieldName, value) {
        var findBaseLoanAmtRatio = ($scope.pricer.appraisedEstimatedValue * $scope.pricer.ltvRatio) /10;
        var findEstimatedValRatio = ($scope.pricer.baseLoanAmount * $scope.pricer.ltvRatio) / 10;
        var findLtvRatio = ($scope.pricer.baseLoanAmount / $scope.pricer.appraisedEstimatedValue) * 10;

        console.log('The fieldName is: ' + (fieldName));
        console.log('The value is: ' + (value));

        if (fieldName !== 'baseLoanAmt' && value != null) {
            console.log('Fire 1');
            $scope.pricer.baseLoanAmount = precisionRound(findBaseLoanAmtRatio, 2);
        }
        if (fieldName !== 'estimatedVal' && value != null) {
            console.log('Fire 2');
            $scope.pricer.appraisedEstimatedValue = precisionRound(findEstimatedValRatio, 2);
        }
        if (fieldName !== 'ltvRatio' && value != null) {
            console.log('Fire 3');
            $scope.pricer.ltvRatio = precisionRound(findLtvRatio, 3);
        }
    };
}]);

Solution

  • https://plnkr.co/edit/BFlvshCp1Rhs6WpxrjmN?p=preview

    It's probably because at some points in your code you are dividing by zero. You should never divide by a number until you first check that it is not a zero.

    function calcLtv() {
      var findLtvRatio;
        if($scope.pricer.appraisedEstimatedValue === 0) {
          findLtvRatio = 0;
        }
        else {
          findLtvRatio = ($scope.pricer.baseLoanAmount / $scope.pricer.appraisedEstimatedValue) * 10;
        }
        return findLtvRatio;
    }