1

I have an array of data that show in a table, that table is editable, and want the fields are dependent on each other.

How I can do that by changing the percentage of a cell, change the amount for that row and vice versa, when you change the amount, also change the percentage? always verifying not exceeding 100% of the sum of the percentages, and the sum of the amounts not exceeding the total amount.

angular
.module("app", [])
.controller("appController", function ($scope) {

  $scope.Data = [
    {
      Percent: 25.0,
      Value: 1000.0
    },
    {
      Percent: 25.0,
      Value: 1000.0
    },
    {
      Percent: 25.0,
      Value: 1000.0
    },
    {
      Percent: 25.0,
      Value: 1000.0
    }
  ];
  $scope.TotalAmount = 4000.0;
});
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <link rel="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" type="text/css" />

</head>
<body ng-app="app">

    <div class="container" ng-controller="appController">
      Total amount: {{TotalAmount}}
        <table class="table table-striped">
          <tr><th>Percent</th><th>Value</th></tr>
            <tr ng-repeat="invoice in Data">
                <td><input type="number" ng-model="invoice.Percent" /></td>
                <td><input type="number" ng-model="invoice.Value" /></td>
            </tr>
        </table>
    </div>

</body>
</html>

1
  • Basically its weirdo! but you can add ng-change event on input box, based on total value or % update other row value & %. As you need to do some calculation for other row based on whichever row you making changes. Update other row with equal value like((total value- change row)/(total number of rows-1)) Or you can make the random number generation and make sure its validate with total value and %, it will have lots of permutations & combinations so better use above metioned case. Commented Sep 29, 2016 at 6:10

5 Answers 5

3

You can use ng-change for each input(just like @Pravin Erande said in comments).

I have made a SAMPLE FIDDLE for you(without any calculations)

<tr ng-repeat="invoice in Data">
                <td><input type="number" ng-model="invoice.Percent" ng-change="valueChanged($index,invoice.Percent,invoice.Value)" /></td>
                <td><input type="number" ng-model="invoice.Value" ng-change="valueChanged($index,invoice.Percent,invoice.Value)" /></td>
            </tr>



$scope.valueChanged= function(index,precent,value)
  {
    console.log("Index changed "+index+" percent "+precent+" value "+value);
    $scope.Data[index].Percent = 50; // Assign after calculation
$scope.Data[index].Value = 2000; // Assign after calculation
  }

You can create a function and pass the $index to that function and update the $scope.Data accordingly after calculation

Sign up to request clarification or add additional context in comments.

Comments

0

Add ng-change event on bothinput box

angular
.module("app", [])
.controller("appController", function ($scope) {

  $scope.Data = [
    {
      Percent: 25.0,
      Value: 1000.0
    },
    {
      Percent: 25.0,
      Value: 1000.0
    },
    {
      Percent: 25.0,
      Value: 1000.0
    },
    {
      Percent: 25.0,
      Value: 1000.0
    }
  ];
  $scope.TotalAmount = 4000.0;
  $scope.percentChange=function(index,percent){
     var remainpercent=(100-percent)/($scope.Data.length-1);
     var changerowvalue =$scope.TotalAmount*(percent/100);
     $scope.Data[index].Value=changerowvalue;
     var remainValue=($scope.TotalAmount-changerowvalue)/($scope.Data.length-1);
     for(var i=0;i<$scope.Data.length;i++){
       if(i!==index){
           $scope.Data[i].Percent=remainpercent;
           $scope.Data[i].Value=remainValue;
       }
     }
  };
   $scope.valueChange=function(index,value){
     $scope.Data[index].Percent=(value*100/$scope.TotalAmount);
     var remainValue=($scope.TotalAmount-value)/($scope.Data.length-1);
     var remainpercent=(100-$scope.Data[index].Percent)/($scope.Data.length-1);        
     for(var i=0;i<$scope.Data.length;i++){
       if(i!==index){
           $scope.Data[i].Percent=remainpercent;
           $scope.Data[i].Value=remainpercent;
       }
     }
  };
});
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <link rel="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" type="text/css" />

</head>
<body ng-app="app">

    <div class="container" ng-controller="appController">
      Total amount: {{TotalAmount}}
        <table class="table table-striped">
          <tr><th>Percent</th><th>Value</th></tr>
            <tr ng-repeat="invoice in Data">
                <td><input type="number" ng-change="percentChange($index,invoice.Percent)" ng-model="invoice.Percent" /></td>
                <td><input type="number" ng-change="valueChange($index,invoice.Percent)" ng-model="invoice.Value" /></td>
            </tr>
        </table>
    </div>

</body>
</html>

I haven't added negative cases like posting value greater than total value or for % more than 100

Comments

0

You can achieve it by calling a single function based on the flag.

See the working example.

  angular
.module("app", [])
.controller("appController", function ($scope) {

  $scope.Data = [
    {
      Percent: 25.0,
      Value: 1000.0
    },
    {
      Percent: 25.0,
      Value: 1000.0
    },
    {
      Percent: 25.0,
      Value: 1000.0
    },
    {
      Percent: 25.0,
      Value: 1000.0
    }
  ];
  $scope.TotalAmount = 4000.0;
  
  $scope.changeCalled = function(invoice, flag, index){
    var per=0;
    var value=0;
    if(flag == 'per')
    {
        value = ($scope.TotalAmount * invoice.Percent)/100;
        $scope.Data[index].Value = value;
    }
    else if(flag == 'val')
    {
        per = (invoice.Value * 100) / $scope.TotalAmount;
        $scope.Data[index].Percent = per;
    }
    $scope.updateResult(index);
  }
  $scope.updateResult = function(index, flag){
    var remainedPer = 0;
    var remainedVal = 0;
    remainedPer = (100 - $scope.Data[index].Percent)/ ($scope.Data.length - 1);             
    remainedInput = ($scope.TotalAmount - $scope.Data[index].Value)/ ($scope.Data.length - 1); 
    for(i=0; i<$scope.Data.length; i++)
    {
        if(i != index)
        {   
            $scope.Data[i].Percent = remainedPer;
            $scope.Data[i].Value = remainedInput;
        }
    }
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">

    <div class="container" ng-controller="appController">
      Total amount: {{TotalAmount}}
        <table class="table table-striped">
          <tr><th>Percent</th><th>Value</th></tr>
            <tr ng-repeat="invoice in Data">
                <td><input type="number" ng-model="invoice.Percent" ng-change="changeCalled(invoice, 'per', $index)"/></td>
                <td><input type="number" ng-model="invoice.Value" ng-change="changeCalled(invoice, 'val' ,$index)" /></td>
            </tr>
        </table>
    </div>

</body>

Comments

0

Thank you all! I took a bit of everyone's comments, but I think it helped me with my problem was ng-change.

I leave an example of what I needed to do.

Regards!

angular
            .module("app", [])
            .controller("appController", function ($scope, $filter) {

                $scope.Data = [
                  {
                      Percent: 25.0,
                      Value: 1000.0
                  },
                  {
                      Percent: 25.0,
                      Value: 1000.0
                  },
                  {
                      Percent: 25.0,
                      Value: 1000.0
                  },
                  {
                      Percent: 25.0,
                      Value: 1000.0
                  }
                ];
                $scope.TotalAmount = 4000.0;

                $scope.ValueChanged = function (invoice) {
                    invoice.Value = (invoice.Value == null || invoice.Value.toString() == ".") ? 0 : invoice.Value;
                    invoice.Percent = (invoice.Value * 100.0) / $scope.TotalAmount;
                    CalculateTotals();
                    ValidateValues();
                }

                $scope.PercentChanged = function (invoice) {
                    invoice.Percent = (invoice.Percent == null || invoice.Percent.toString() == ".") ? 0 : invoice.Percent;
                    invoice.Value = $scope.TotalAmount * (invoice.Percent / 100.0);
                    CalculateTotals();
                    ValidateValues();
                }

                function CalculateTotals() {
                    var sumPercent = 0;
                    var sumAmount = 0;
                    angular.forEach($scope.Data, function (item, index) {
                        sumPercent += item.Percent;
                        sumAmount += item.Value;
                    });
                    $scope.CalculatedPercent = sumPercent;
                    $scope.CalculatedAmount = sumAmount;
                }

                function ValidateValues() {
                    IsValidAmount();
                    IsValidPercent();
                }

                function IsValidPercent() {
                    if ($scope.CalculatedPercent == 100.0) {
                        $scope.IsValidPercent = true;
                        $scope.formInvoices.hdCalculatedPercent.$setValidity('valid', true);
                    } else {
                        $scope.IsValidPercent = false;
                        $scope.formInvoices.hdCalculatedPercent.$setValidity('valid', false);
                    }
                }

                function IsValidAmount() {
                    if ($scope.CalculatedAmount == $scope.TotalAmount) {
                        $scope.IsValidAmount = true;
                        $scope.formInvoices.hdCalculatedAmount.$setValidity('valid', true);
                    } else {
                        $scope.IsValidAmount = false;
                        $scope.formInvoices.hdCalculatedAmount.$setValidity('valid', false);
                    }
                }

                $scope.CalculatedPercent = 100.0;
                $scope.CalculatedAmount = $scope.TotalAmount;

                $scope.IsValidPercent = true;
                $scope.IsValidAmount = true;
            })
.invalidValue{
            color: red;
            font-weight: bold;
        }
        .validValue{
            color: black;
        }
        .tableWidth{
            width: 500px;
        }
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
   
   
</head>
<body ng-app="app">

    <div class="container" ng-controller="appController">
        <form role="form" name="formInvoices">
            <table class="table table-condensed table-bordered tableWidth">
                <tr>
                    <td class="col-xs-12"><b>Total amount: </b>{{TotalAmount | currency}}</td>
                </tr>
            </table>
            <table class="table table-striped  table-condensed table-bordered tableWidth">
                <tr>
                    <th>Percent</th>
                    <th>Amount</th>
                </tr>
                <tr ng-repeat="invoice in Data">
                    <td><input type="number" ng-model="invoice.Percent" ng-change="PercentChanged(invoice)" /> %</td>
                    <td>$ <input type="number" ng-model="invoice.Value" ng-change="ValueChanged(invoice)" /></td>
                </tr>
            </table>
            <table class="table table-striped table-condensed table-bordered tableWidth">
                <tr>
                    <td class="col-xs-6" ng-class="{'invalidValue': !IsValidPercent,'validValue': IsValidPercent}">{{CalculatedPercent}} %<input name="hdCalculatedPercent" type="hidden" ng-model="CalculatedPercent" /></td>
                    <td  class="col-xs-6" ng-class="{'invalidValue': !IsValidAmount,'validValue': IsValidAmount}">{{CalculatedAmount | currency}}<input name="hdCalculatedAmount" type="hidden" ng-model="CalculatedAmount" /></td>
                </tr>
            </table>
            <input type="submit" ng-disabled="formInvoices.$invalid" value="Save" />
        </form>
    </div>

</body>
</html>

Comments

0

Below is Logic for your need!.

$scope.Data[index].Percent = value/$scope.TotalAmount * 100;

$scope.Data[index].Value = precent/100 * $scope.TotalAmount;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.