3

So I've this bunch of JSON data and I wanna do some calculations and append the results and create a new key in the JSON. I've setup the calculation services which I then use in the controller. But the issue is, is that it is only pushing in the last known value into each newly created 'rate' key.

The JSON is like this:

[{  "date"      : "2015-09-01",
"start"     : "2015-09-01 08:00:00",
"finish"    : "2015-09-01 10:00:00",
"loggedIn"  : "2015-09-01 08:06:27",
"loggedOut" : "2015-09-01 10:06:27"

}, { "date"      : "2015-09-02",
 "start"     : "2015-09-02 08:00:00",
 "finish"    : "2015-09-02 10:00:00",
 "loggedIn"  : "2015-09-02 08:02:05",
 "loggedOut" : "2015-09-02 10:02:11"

}, { "date"      : "2015-09-03",
 "start"     : "2015-09-03 13:00:00",
 "finish"    : "2015-09-03 14:30:00",
 "loggedIn"  : "2015-09-03 13:11:05",
 "loggedOut" : "2015-09-03 14:31:01"

}, { "date"      : "2015-09-04",
 "start"     : "2015-09-04 13:00:00",
 "finish"    : "2015-09-04 14:30:00",
 "loggedIn"  : "2015-09-04 13:01:05",
 "loggedOut" : "2015-09-04 14:31:01"

}, { "date"      : "2015-09-05",
 "start"     : "2015-09-05 18:00:00",
 "finish"    : "2015-09-05 21:00:00",
 "loggedIn"  : "2015-09-05 18:30:05",
 "loggedOut" : "2015-09-05 21:00:51"

}]

The service is as follows:

angular.module('appService', [])
.service('CalculationService', function(){
    this.getTheRate = function(start, end, login) {
        if ( typeof (start) && typeof (end) && typeof (login) === 'undefined') {
            return 'n/a';
        } else {
            var startTime =  new Date(start).getTime() / 60000,
                endTime   =  new Date(end).getTime()   / 60000,
                loginTime =  new Date(login).getTime() / 60000;

            var totalTime  = endTime - startTime,
                lateness   = loginTime - startTime,
                percentile = 100 - (lateness / totalTime) * 100;

            return parseFloat(percentile).toFixed(1);
        }
    };

The controller like this:

angular.module('MainController', [])
 .controller('mainCtrl', [
    '$http', 
    'CalculationService', 
    function($http, CalculationService){

         var logins = this;

         logins.dataStore = [];

         logins.add = function(temp){
             logins.dataStore.push(temp);
         };

         $http.get('./theData.json').success(function(data){
            logins.data = [];
            logins.data = data;
         });

         logins.getRate = function(start, end, login) {
            angular.forEach(logins.data, function(obj){
                obj.rate = {};
                obj.rate = CalculationService.getTheRate(start, end, login);
                return obj.rate;
            });
         };
}]);

Markup like so :

<div ng-controller="mainCtrl as main">
<section class="view-section">
            <div class="view" ng-repeat="item in main.data"> 
                {{ main.getRate(item.start, item.finish, item.loggedIn) }}
                {{ item.rate }}
            </div>
</section>
</div>

{{ item.rate }} outputs just fine within ngRepeat but when I checked the data via {{ main.data }} the key is created for each instance but the value however is not inserted properly whereby all 'rate' keys are all assigned the same last known calculated value instead of distinct calculated values for each instance. Any ideas?

2
  • DON'T invoke a function with side-effects inside a watched expression {{ ... }} Commented May 12, 2015 at 4:43
  • Regardless of your question, checking typeof(start) && typeof(finish) && typeof(login) === 'undefined' probably doesn't do what you intended. Commented May 12, 2015 at 7:14

1 Answer 1

1

Your getRate function invokes the calculation in a loop over all the data (using angular.forEach), but using the same start, finish and login values. Then you call this function inside the ngRepeat which creates a second loop. So every iteration of the ngRepeat loop assigns the rate of the current item to all the items. This is why by the time you're done all items have the rate of the last item.

Instead, invoke the rate calculation loop in the controller, right after getting the data (literally right after assigning logins.data in the $http.get callback), and not in a {{…}} expression. As the comments mention, it's not a good idea to invoke a function with side effects inside an expression.

Also note that this error was made possible because your getRate function both assigns the rate to the object (actually, to all objects) and returns it. That's confusing and error-prone. It would be easier if the function either assigned the rate or returned it, but not both.

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

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.