javascripteach.post

Javascript Return loop sum


I'm running a sequence of 3 ajax posts and in the end i need to sum devices from a while loop inside a each loop. First i get the session id, then i get the number of devices and do a foreach loop to get ids of each device. After that i make a while loop to increase per month from start date until today date and get total device month consumption and sum. I need the total consumption of all devices months consumptions together.

I did comment in the middle of functions where i can sum, and where i get value 0. I even tried runing a separate function which is in the last comment at the end but it kept returning undefined.

Hope u can understand the idea.

var SESSION_ID ='';
var total = parseFloat(0.0);
$.post("http://xxx.xxxxxxxx.com/users/auth", {
    token : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    }, function (session) {
        if(session) {
            console.log("Session id received.");
            SESSION_ID = session.id;
            console.log("Looking for devices.");
            $.post("http://xxx.xxxxxxxxxxxxxxx.com/devices/list", {
                id : session.id
            }, function (devices) {
                if(devices) {

                    /* Loop trough devices to get id of each device */
                    $.each(devices, function(index, val) {

                         /* Set start date */
                        var targetDate = new Date();
                        targetDate.setFullYear(2015);
                        targetDate.setMonth(2);
                        targetDate.setDate(1);
                        targetDate.setHours(0);
                        targetDate.setMinutes(0);
                        targetDate.setSeconds(0);
                        var currentDate = new Date();

                        /* Increase 1 month until current date */
                        while (targetDate.getMonth() !== currentDate.getMonth() || targetDate.getFullYear() !== currentDate.getFullYear()) {
                            //console.log("Month: " + (targetDate.getMonth() + 1) + "; Year: " + targetDate.getFullYear());
                            var month = targetDate.getMonth() + 1,
                                year = targetDate.getFullYear();

                            $.post("http://xxx.xxxxxxxxxxxxxx.com/devices/" + val.id + "/consumptions?year=" + year + "&month=" + month + "&resolution=month", {
                                id : SESSION_ID
                            }, function (consumptions) {
                                if(consumptions) {
                                    $.each(consumptions, function(index, val) {
                                         /* Sum each month consumption value */
                                         if(val.value !== '') {
                                            total += val.value;
                                         }
                                    });

                                    // Return values float values Eg.: 11774.86060142517 and keeps
                                    console.log(total);
                                }
                            }, "json");
                            // Increase month
                            targetDate.setMonth(targetDate.getMonth() + 1);

                            // console.log(total) returns 0
                            console.log(total);
                        }
                    });

                    // Total returning 0
                    // console.log(total);
                } else {
                    console.log("No devices found.");
                }
            }, "json");
        } else {
            console.log("No session id");
        }
    }, "json");

    /*
    function getMonthConsumption(device_id, device_year, device_month) {
        $.post("http://xxx.xxxxxxxxxxxxxx.com/devices/" + device_id + "/consumptions?year=" + device_year + "&month=" + device_month + "&resolution=month", {
            id : SESSION_ID
        }, function (consumptions) {
            if(consumptions) {
                $.each(consumptions, function(index, val) {

                     if(val.value !== '') {
                        total = total + val.value;
                     }
                });
                return consumptions;
            }
        }, "json");
    }
    */
});

Solution

  • The $.post you do for each device consumption per month in the while loop is async and therefor the code execution continues right to the printing part where you get 0. If you log the value to the console after all posts you will see that the result is correctly calculated. To see this in your example remove all console.log calls and replace the line total += val.value; with a function which adds to the global value and logs the new value in the console eg.:

    function addToTotal(value) {
      total += value;
      console.log(total);
    }
    
    ...
    /* Sum each month consumption value */
    if(val.value !== '') {
      addToTotal(val.value);
    }
    ...
    

    To detect when all of the posts finished and then calculate total sum you can use jQuery promises since the $.post method already returns one. Have a look at jQuery.when()

    EDIT

    Based on the comment here is a proposed solution with jQuery promises. First add an array of promises where you will keep all your requests for consumption and then gather all responses and process them:

    var SESSION_ID ='';
    var total = parseFloat(0.0);
    
    $.post("http://xxx.xxxxxxxx.com/users/auth", {
        token : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        }, function (session) {
            if(session) {
                console.log("Session id received.");
                SESSION_ID = session.id;
                console.log("Looking for devices.");
                $.post("http://xxx.xxxxxxxxxxxxxxx.com/devices/list", {
                    id : session.id
                }, function (devices) {
                    if(devices) {
    
                        var promises = [];
    
                        /* Loop trough devices to get id of each device */
                        $.each(devices, function(index, val) {
    
                             /* Set start date */
                            var targetDate = new Date();
                            targetDate.setFullYear(2015);
                            targetDate.setMonth(2);
                            targetDate.setDate(1);
                            targetDate.setHours(0);
                            targetDate.setMinutes(0);
                            targetDate.setSeconds(0);
                            var currentDate = new Date();
    
                            /* Increase 1 month until current date */
                            while (targetDate.getMonth() !== currentDate.getMonth() || targetDate.getFullYear() !== currentDate.getFullYear()) {
                                //console.log("Month: " + (targetDate.getMonth() + 1) + "; Year: " + targetDate.getFullYear());
                                var month = targetDate.getMonth() + 1,
                                    year = targetDate.getFullYear();
    
                                var postPromise = $.post("http://xxx.xxxxxxxxxxxxxx.com/devices/" + val.id + "/consumptions?year=" + year + "&month=" + month + "&resolution=month", {
                                    id : SESSION_ID
                                }, "json");
                                promises.push(postPromise);
    
                                // Increase month
                                targetDate.setMonth(targetDate.getMonth() + 1);
                            }
                        });
    
                        // Gather all responses
                        $.when.apply($, promises).then(function() {
                            var total = 0;
                            // Here arguments will have the responses from all $.post requests added to the promises array. The actual respo
                            $.each(arguments, function(index, jqueryPostResponses) {
    
                                var consumptions = jqueryPostResponses[0] // first object is the data;
    
                                $.each(consumptions, function(index, val) {
                                    /* Sum each month consumption value */
                                    if(val.value !== '') {
                                        total += val.value;
                                    }
                                });
    
                            });
    
                            return total;
                        }).then(doSomethingWithTotal);
    
                    } else {
                        console.log("No devices found.");
                    }
                }, "json");
            } else {
                console.log("No session id");
            }
        }, "json");
    
        function doSomethingWithTotal(totalSum) {
            $('#totalSum').text(totalSum);
        }
    });
    

    Since I can't test this code without knowing the actual responses you may need to tweak the code to make it work. Here is a working JSFiddle to help you.

    For recurrent execution wrap the $.post for devices in a new function that will be run with setInterval(theNewFunction, 1000 /* repeat interval in ms */);