agon024
agon024

Reputation: 1007

AngularJS - Grabbing multiple JSON key values and then adding them together

Here is the code for my angular code:

  angular.module('ngApp', [])
  .factory('authInterceptor', authInterceptor)
  .constant('API', 'http://appsdev.pccportal.com:8080/ecar/api')
  .controller('carDetails', carDetails)

  function carDetails($scope, $http, API) {
    $http.get( API + '/car/12208' ).
    success(function(data) {
      $scope.details = data;
    });
  }

Here is a pic of the JSON data I am working with:

enter image description here

As you can see under Financial Info I have multiple keys that have currency values in them. How can I pull out those values in angular and add them together and then display that result in my HTML file.

I can obviously get land_curr and land_prev values in the html by using

{{ details['Financial Info'].land_curr }}

But in the HTML that I have been given there is a spot for "total amount". So I need to take those values, add them together and then put that new value into the "total amount" section in the HTML file.

Is there a way I can do this?

EDIT:

Note that these JSON values will change so I cant "hard code" the currency values into anything as the currency amounts will change often. Also I need to be able to add all "_prev" values together and "_curr" values together. And I need to just be able to add, for instance, "land_curr" and "land_prev" together too.

Upvotes: 4

Views: 2194

Answers (5)

agon024
agon024

Reputation: 1007

OK. So I finally got this working. Thank you to @amirsasson for getting the ball rolling and everyone else here who gave me the info that they did. I really appreciate it.

So you can obviously subtract, divide and multiply expression values by using:

{{ details['Financial Info'].land_curr - details['Financial Info'].land_prev }}

{{ details['Financial Info'].land_curr / details['Financial Info'].land_prev }}

{{ details['Financial Info'].land_curr * details['Financial Info'].land_prev }}

But when I tried to add them as per @amirsasson solution it would not sum up the two values it would just put them side by side.

So What I had to do was multiply the values in the expression by 1 and then add them together like so:

${{ (details['Financial Info'].land_curr * 1 ) + (details['Financial Info'].land_prev * 1) }}

This worked exactly how I needed it to.

Thanks for everyones help.

Upvotes: 0

Andrew Mairose
Andrew Mairose

Reputation: 10995

I would recommend calling a function from your html to get the total. That way, if the values in your 'Financial Info' object change dynamically, the total would be updated as well. See the example I have provided below. (I also threw in an ng-repeat to list all of the 'Financial Info', as well as the currency filter in case you didn't know about those).

In the example, I just hard coded your example object into the $scope.details variable. In your actual application, you can still populate this the same way you were - using the $http service to call your API.

You can add a function, called getTotal() for example, to the controller's $scope. That way, you can call it directly from your html using {{getTotal()}}.

In the getTotal() method, you can just utilize angular's built in forEach() method (or just plain old vanilla javascript if you prefer) to loop through every item in the 'Financial Info' object. Then, you just need to call parseInt() passing in the value, since they are strings in your object, then add it to a running sum variable. Finally, you can return the sum after angular's forEach() is complete.

EDIT: Added methods for getting the total of all _curr values and _prev values, as well as land_.

EDIT 2: Added a timeout to simulate the data loading via your $http call. To avoid getting the error with $scope.details being null until your $http call returns, you can either add if (!$scope.details) { return; } at the beginning of each of your getTotal functions, or you could initialize $scope.details with null or blank values for each of the items that you expect your $http call to return. For example, in the snippet below, I initialized the $scope.details variable as such:

$scope.details = {
  'Executive Summary': null,
  'Financial Info': {},
  ID: null
};

Working Example:

angular.module('ngApp', [])
  .controller('carDetails', carDetails);

function carDetails($scope, $timeout) {
  $scope.details = {
    'Executive Summary': null,
    'Financial Info': {},
    ID: null
  };

  $scope.loading = true;
  $timeout(function() {
    $scope.details = {
      'Executive Summary': "This is a test. Please ignore.",
      'Financial Info': {
        alt_curr: "1000",
        alt_prev: "500",
        auto_curr: "2100",
        bldgs_curr: "12000",
        bldgs_prev: "5000",
        land_curr: "30000",
        land_prev: "700",
        machine_curr: "25000",
        machine_prev: "1000",
        other_curr: "2659",
        other_exp_curr: "900",
        other_exp_expl: "9800",
        other_exp_prev: "600",
        other_prev: "6000",
        startup_curr: "600",
        startup_prev: "550"
      },
      ID: 12208
    };
    $scope.loading = false;
  }, 5000);

  $scope.getTotal = function() {
    var sum = 0;
    angular.forEach($scope.details['Financial Info'], function(value, key) {
      sum += parseInt(value, 10);
    });
    return sum;
  }

  $scope.getCurrTotal = function() {
    var sum = 0;
    angular.forEach($scope.details['Financial Info'], function(value, key) {
      if (key.substring(key.length - 5) == '_curr') {
        sum += parseInt(value, 10);
      }
    });
    return sum;
  }

  $scope.getPrevTotal = function() {
    var sum = 0;
    angular.forEach($scope.details['Financial Info'], function(value, key) {
      if (key.substring(key.length - 5) == '_prev') {
        sum += parseInt(value, 10);
      }
    });
    return sum;
  }

  $scope.getLandTotal = function() {
    var sum = 0;
    angular.forEach($scope.details['Financial Info'], function(value, key) {
      if (key.substring(0, 4) == 'land') {
        sum += parseInt(value, 10);
      }
    });
    return sum;
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ngApp" ng-controller="carDetails" ng-cloak>
  <div ng-show="!loading">
    <div ng-repeat="(key, value) in details['Financial Info']">
      <span>{{key}}: {{value|currency}}</span>
    </div>
    <hr/>
    <span>TOTAL: {{getTotal()|currency}}</span>
    <br>
    <span>Current Total: {{getCurrTotal()|currency}}</span>
    <br>
    <span>Previous Total: {{getPrevTotal()|currency}}</span>
    <br>
    <span>Land Total: {{getLandTotal()|currency}}</span>
  </div>
  <div ng-show="loading">
    Simulating data loading by using a timeout...
  </div>
</div>

Upvotes: 2

Steve Padmore
Steve Padmore

Reputation: 1740

Unfortunately, if the keys in your list can be altered at any time, you could never write code to sum groups together that would work forever. As soon as an additional key was added, changed, or one completely removed, your code would fail and need to be re-written.

I get the feeling that the data you are receiving is not produced by yourself, but if you can request it is supplied in a usable format, you'll be able to write the code you need. If however you cannot change this, then you'll have to do some string manipulation to place the data items and values into groups you can use - but you will never know what that data really is - they'll just be strings.

As a hack, you could get each item Financial Info object (the key/value pairs), and when passing them through an 'each' function split the key on the underscore and check for your 'curr' and 'prev' values (or pair up the 'bldgs', 'land' etc.), then sum them accordingly. However, I noticed that there is also an 'expl' in one of the keys - this is why any changes may break what you do.

The only way to do this correctly would be to generate a proper JSON object that can tell you what the items are and what values they have. This is the purpose of structured data in models - a string and a value doesn't give you enough to work on.

So a rough example could be:

{
    'Executive Summary': "This is a test. Please ignore.",
    'Financial Info': {
      alt: { curr: "1000", prev: "500"},
      auto: {curr: "2100"},
      bldgs: {curr: "12000", prev: "5000"},
      land: {curr: "30000", prev: "700"},
      machine: {curr: "25000", prev: "1000"},
      other: {curr: "2659", prev: "6000", exp: { curr: "900", expl: "9800", prev: "600"}},
      startup: {curr: "600", prev: "550"},
    },
    ID: 12208
 }

Now you can loop through looking for all items with a 'curr' or 'prev' value, and sum them. Or you can sum the 'curr' and 'prev' for each item in the list. It won't matter what the items names are in the future - you read the name from the JSON object and display its summed values.

So, loop through each item outputting its name and summed values:

Land : "1500" (land.curr, land.prev)

Machine : "26,000" (machine.curr, machine.prev) etc.

Loop through all adding the 'curr', 'prev', and 'expl' as required:

Total Curr: 74,259 (alt.curr, auto.curr, bldgs.curr, land.curr, machine.curr, other.curr, other.exp.curr, and startup.curr)

Total Prev: 14,350 (alt.prev, bldgs.prev, land.prev, machine.prev, other.prev, other.exp.prev, startup.prev)

Total Expl: 9800 (other.exp.expl)

This is only a quick explanation, but you could also change the pure 'objects' above to arrays of 'Items' where each one has a 'Name' and an array of 'Data', each 'Data' item having a 'Type' and a 'Value'.

Upvotes: 0

Naveen
Naveen

Reputation: 830

Did you try forEach in Angular ? See below:

angular.module('myApp', []).controller('carDetails', ['$scope', function(scope) {
             var vm = this;
             vm.obj = {'Financial Info':{
                alt_curr : "1000", alt_prev : "2000"
             }}
             vm.sum = 0;
             angular.forEach(vm.obj['Financial Info'], function(val, key){
                vm.sum +=parseInt(val);
             });
             console.log(vm.sum)
         }]);

Edit: In your html, you can display the variable as shown below:

<html>
<div ng-app="myApp" ng-controller="carDetails as vm">
{{vm.sum}}
</div>
</html

Upvotes: 0

Amir Sasson
Amir Sasson

Reputation: 11493

Since JS is a dynamic language you can add a new property/method to 'Financial Info' that does the mathematics. like:

  details['Financial Info'].calcTotalLand= function(){return this.land_prev+ this.land_curr;};

you can also just write in your HTML

{{ details['Financial Info'].land_curr + details['Financial Info'].land_prev}}

if possible

Upvotes: 2

Related Questions