1

I am trying to use angular http post inside a loop using angular forEach as advised here- Angular HTTP Get on loop and Angularjs loop trought $http.post but the solution is not working in my case. The http post always returns result with respect to the last item in LifeBenefitTRAD but I want the result for each item in the loop. e.g. If I have 4 items in the list of LifeBenefitTRAD, my post method is executing 4 times but w.r.t the fourth item in the list.enter image description here The execution always happens with respect to last object.Please tell me what am I doing wrong here?-

   $scope.GenerateAllTradQuote = function () {
        var TRADPlanDetails = {};
        console.log(LifeBenefitTRAD);
        //for (var i = 0; i < LifeBenefitTRAD.length; i++) {
        LifeBenefitTRAD.forEach(function (trad) {
           TRADPlanDetails.QuoteName = "TradQuote_" + trad.LifeBenefitValue;
           TRADPlanDetails.LifeBenefitId = trad.LifeBenefitId;
           TRADPlanDetails.LifeBenefitValue = trad.LifeBenefitValue;

            console.log(TRADPlanDetails);

            $http({
                url: key_Url_GenerateTradQuote,
                method: key_String_HttpPost,
               // async: true,
                params: TRADPlanDetails
            }).then(function (result) {
                $scope.TRAD_PlanDetails.TRAD_DisplayFlag = true;
                if (result.data != key_String_Zero) {

                    $scope.TRAD_PlanDetails.TRAD_DisplayMsg = key_Confirm_Successful_Quote;
                }
                else {
                    $scope.TRAD_PlanDetails.TRAD_DisplayMsg = key_Confirm_failed_Quote;
                }
            });
        });
       // }
    };
Community
  • 1
  • 1
Anil kumar
  • 525
  • 2
  • 10
  • 32
  • 1
    In order for us to help we need to know exactly what's happening, why it's wrong, and what you expect or want to happen. –  Jan 29 '15 at 21:01
  • 3
    Looks like you are updating the same scope variable.. ? But not sure what you want to do.. – smk Jan 29 '15 at 21:02
  • Hi, I have edited my question..please let me know if it's still unclear. – Anil kumar Jan 29 '15 at 21:06
  • I have already edited my question to make it clear then why is this negative vote ? – Anil kumar Jan 29 '15 at 21:13
  • 1
    @Anilkumar I didn't downvote, but you're overwriting the same set of scope properties in every iteration. How is that supposed to work? – JLRishe Jan 29 '15 at 21:27
  • @JLRishe I have removed the scope variables and now using a local variable, but even in this case, post method is working 3 times for the last assigned value to the variable. – Anil kumar Jan 29 '15 at 21:33
  • @Anilkumar Thank you, but what is this code supposed to _do_? Can you explain its purpose in plain English? For example, why are you comparing `result.data` to `key_String_Zero`? What is the objective? It still seems that you are overwriting `TRAD_DisplayMsg` three times, and only the last value is going to remain. – JLRishe Jan 29 '15 at 21:43
  • This piece of code is used in my code for some other reason and not related to the problem. The url in the post is an action method of a controller class in asp .net MVC which will perform some operation. This action method is getting executed 4 times w.r.t the last item in the list. – Anil kumar Jan 29 '15 at 21:47
  • @Anilkumar What observation is leading you to believe that only the last item in the list is being used? – JLRishe Jan 29 '15 at 21:48
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/69852/discussion-between-anil-kumar-and-jlrishe). – Anil kumar Jan 29 '15 at 21:49
  • The method will do something in the back end resulting in creation of 4 pdf files. The data which I am getting in these pdf files are same and w.r.t the calculation based on 4th item in the list – Anil kumar Jan 29 '15 at 21:55

2 Answers2

2

You are declaring the TRADPlanDetails variable outside of the forEach callback, which means that you are passing the same object to $http every time. If there is some delay before $http actually uses your values, then it will wind up using the same set of values for all of its requests.

Please try creating a new variable and a new object each time:

LifeBenefitTRAD.forEach(function (trad) {
    var planDetails = {
        QuoteName: "TradQuote_" + trad.LifeBenefitValue,
        LifeBenefitId: trad.LifeBenefitId,
        LifeBenefitValue: trad.LifeBenefitValue
    };

    $http({
        url: key_Url_GenerateTradQuote,
        method: key_String_HttpPost,
        // async: true,
        params: planDetails
    })
    // ....
});

If maintaining the order of the original requests is important, you can do the following, but be aware that it will slow the process down because it will essentially wait for each request to finish before beginning the next one:

LifeBenefitTRAD.reduce(function (p) {
    var planDetails = {
        QuoteName: "TradQuote_" + trad.LifeBenefitValue,
        LifeBenefitId: trad.LifeBenefitId,
        LifeBenefitValue: trad.LifeBenefitValue
    };

    return p.then(function () {
        return $http({
            url: key_Url_GenerateTradQuote,
            method: key_String_HttpPost,
            // async: true,
            params: planDetails
        });
    })
    .then(function (result) {
        // handle result for current request
    });
}, $q.when());

The above requires using the $q service.

There may be a way to do some low-level stuff with $http that would allow you to initiate a new request right as the previous one was about to be sent off, but from what I can see, it doesn't provide anything that would easily facilitate that.

JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • This seems working but not in the order the parameters are fed. Can we do anything so that post happens in the same order w.r.t the items in the loop? – Anil kumar Jan 29 '15 at 22:08
  • How will it execute in FIFO order? – Anil kumar Jan 29 '15 at 22:13
  • @Anilkumar The only easy solution involving `$http` that I can think of is to do the requests one at a time. Please see my edit. – JLRishe Jan 29 '15 at 22:20
1

JLRishe's answer is part of it, but you also want to store the results differently, so you might want to consider doing something like this:

$scope.GenerateAllTradQuote = function () {
    // Clear out existing details
    $scope.TRAD_PlanDetails = {};

    // This is more compatible than Array.forEach()
    angular.forEach(LifeBenefitTRAD, function (trad) {
        var planDetails = {
            QuoteName: "TradQuote_" + trad.LifeBenefitValue,
            LifeBenefitId: trad.LifeBenefitId,
            LifeBenefitValue: trad.LifeBenefitValue
        };

        $http({
            url: key_Url_GenerateTradQuote,
            method: key_String_HttpPost,
            params: TRADPlanDetails
        }).then(function (result) {
            planDetails.TRAD_DisplayFlag = true;

            if (result.data != key_String_Zero) {
                planDetails.TRAD_DisplayMsg = key_Confirm_Successful_Quote;
            } else {
                planDetails.TRAD_DisplayMsg = key_Confirm_failed_Quote;
            }

            $scope.TRAD_PlanDetails[planDetails.QuoteName] = planDetails;
        });
    });
};

You could alternatively use an array to store it and just push the completed planDetails object to it; up to you.

If you wanted to retain the order of request, you could store the LifeBenefitTRAD loop's index:

$scope.GenerateAllTradQuote = function () {
    // Clear out existing details
    $scope.TRAD_PlanDetails = {};

    // This is more compatible than Array.forEach()
    angular.forEach(LifeBenefitTRAD, function (trad, idx) {
        var planDetails = {
            QuoteName: "TradQuote_" + trad.LifeBenefitValue,
            LifeBenefitId: trad.LifeBenefitId,
            LifeBenefitValue: trad.LifeBenefitValue
        };

        $http({
            url: key_Url_GenerateTradQuote,
            method: key_String_HttpPost,
            params: TRADPlanDetails
        }).then(function (result) {
            planDetails.TRAD_DisplayFlag = true;
            planDetails._index = idx;

            if (result.data != key_String_Zero) {
                planDetails.TRAD_DisplayMsg = key_Confirm_Successful_Quote;
            } else {
                planDetails.TRAD_DisplayMsg = key_Confirm_failed_Quote;
            }

            $scope.TRAD_PlanDetails[planDetails.QuoteName] = planDetails;
        });
    });
};

...Aaaaaand if you needed to put them into the $scope in an array, in order, you could do something like this:

$scope.GenerateAllTradQuote = function () {
    // Clear out existing details
    var TRAD_PlanDetails = [];

    // This is more compatible than Array.forEach()
    angular.forEach(LifeBenefitTRAD, function (trad, idx) {
        var planDetails = {
            QuoteName: "TradQuote_" + trad.LifeBenefitValue,
            LifeBenefitId: trad.LifeBenefitId,
            LifeBenefitValue: trad.LifeBenefitValue
        };

        $http({
            url: key_Url_GenerateTradQuote,
            method: key_String_HttpPost,
            params: TRADPlanDetails
        }).then(function (result) {
            planDetails.TRAD_DisplayFlag = true;
            planDetails._index = idx;

            if (result.data != key_String_Zero) {
                planDetails.TRAD_DisplayMsg = key_Confirm_Successful_Quote;
            } else {
                planDetails.TRAD_DisplayMsg = key_Confirm_failed_Quote;
            }

            TRAD_PlanDetails.push(planDetails);

            // If at the last entry:
            if (idx >= LifeBenefitTRAD.length - 1) putOnScope();
        });
    });

    function putOnScope() {
        $scope.TRAD_PlanDetails = TRAD_PlanDetails.sort(function(a, b) {
            return a._index - b._index;
        });
    }
};
Community
  • 1
  • 1
floatingLomas
  • 8,553
  • 2
  • 21
  • 27