0

New to angularjs and trying out the promise pattern for the first time -

I have a service utility inside which I have this method -

this.getData= function(url){
        var defer = $q.defer();

        $http({method: 'GET', url: url}).
            success(function(data, status){
                defer.resolve(data);
            })
            .error(function(data, status) {
                defer.reject(status);
            });

        return defer.promise;
    };

Now inside my controller, I am calling a method called A()

   var A = function () {
    $scope.myobjectArray = [];


    return utility.getData("some url").then(funciton(data)
    {

        for (i = 0; i < data.length; i++) {
            $scope.myobjectArray.push(data[i].attribute1, new Array());

        }

    }
    ).
    then(function () {

        return getTheSecondAttributeArray();
    }).catch(function (status) {
//display error

    });


};

var getTheSecondAttributeArray = function () {

    for (i = 0; i < $scope.myObjectArray.length; i++) {
        var secondAttributeArray = [];
        var currentType = $scope.myObjectArray[i];
        utility.getData("some url").then(function (response) {
            for (j = 0; j < response.length; j++) {
//some response manipulation
                secondAttributeArray.push(response[j].text);
            }
        currentType.secondAttribute = secondAttributeArray;
        }).catch(function () {//catch error, display message
        })

    }
}

However, it looks like that the last element of the $scope.myobjectArray (n-1th element) is only getting populated. Also, the secondAttributeArray that this last element contains is a concatenated array of all secondAttributes for all objects of the $scope.myobjectArray.

Cannot figure out what can I change here.

EDIT:

When I tried accessing $scope.myObjectArray[j] inside the 'then' function, it said $scope.myObjectArray[j] was undefined. --> And so I created a currentType variable and assigned $scope.myObjectArray[j] to it and that was easily accessible inside the 'then' function. Weird!

Also, I see that only the last object of the $scope.myObjectArray gets values and not the rest. The rest of the objects in the array are empty

Any help is appreciated.

var myObject = function(firstattribute, secondAttribute){

this.firstattribute = firstattribute;
this.secondAttribute = secondAttribute;
}

The explanation here by Beehive (Angularjs $q.all) is something that I am facing. I only get the last loop's data.

Community
  • 1
  • 1
Tisha
  • 827
  • 3
  • 11
  • 34
  • 5
    http://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it - don't wrap $http in a promise it already returns one – Benjamin Gruenbaum Mar 16 '16 at 15:13
  • I see, so I should remove the defer portion? Also, its weird that when I do the $scope.myObjectArray[i].secondAttributeArray = secondAttributeArray; inside the 'then' function, it says $scope.myObjectArray[i] is undefined. – Tisha Mar 16 '16 at 15:21
  • 1
    It's really, really difficult to figure out what you're trying to do without proper indentation. I attempted to edit but had to make too many assumptions to make the parens and brackets line up. Please edit and add proper indents. – ach Mar 16 '16 at 15:30
  • Done, sorry about that. – Tisha Mar 16 '16 at 15:33
  • what's that `returns` in your code? – Alon Eitan Mar 16 '16 at 15:34
  • Sorry typo. Corrected. – Tisha Mar 16 '16 at 15:38
  • The most obvious issue is that you're assuming you'll see changes to `secondAttributeArray` from code outside of the `then`. At the very least you should move the `$scope.myObjectArray[i].secondAttributeArray = secondAttributeArray;` to the inside of the `then` block. – ach Mar 16 '16 at 15:44
  • Yup, that's my second question in the description. If I do that, it says $scope.myObjectArray[i] is undefined. – Tisha Mar 16 '16 at 15:46
  • I also tried passing $scope.myObjectArray[i] in the then function as a renamed variable currentObject and then did the assignment but I see the same issue of last object having all the secondacctributes assigned to it. – Tisha Mar 16 '16 at 15:51
  • Actually, Now I see that only the last object has a correct value but the rest of the objects do not. Edited the code and description – Tisha Mar 16 '16 at 15:58
  • Any ideas on why the other objects in the $scope.myObjectArray do not get any values for the secondAttribute but only the last object in the array gets secondAttribute.? – Tisha Mar 16 '16 at 16:17
  • Interesting is that when I do a console.log(i) inside the 'then' function, I only see value 5 (the max value). – Tisha Mar 16 '16 at 16:52
  • The explanation here by Beehive (http://stackoverflow.com/questions/21310964/angularjs-q-all) is something that I am facing. I only get the last loop's data. – Tisha Mar 16 '16 at 17:34
  • Why are you using push(..., new Array())? You might not want this – Renan Ferreira Mar 16 '16 at 17:34
  • I am just assigning it so that in the second method I don't have to , but I can set it to null as well. – Tisha Mar 16 '16 at 17:35
  • push() receives one or more elements to add to an array. That way, you are adding an empty array every iteration. – Renan Ferreira Mar 16 '16 at 17:37
  • Changed that but that does not really help :( As added in my previous comment, the explanation here by Beehive (stackoverflow.com/questions/21310964/angularjs-q-all) is something that I am facing. I only get the last loop's data. – Tisha Mar 16 '16 at 17:44

1 Answers1

1

The issue is all in function closures. When the get data returns, your currentType is the last one because the for j loop ended already. So what you need to do is move the code starting from utility.getData to a separate method passing the parameters of the currentType and the seccondAttributeArray so the closure will contain them as parameters of the function and not change them as the for j loop progresses.

for (i = 0; i < $scope.myObjectArray.length; i++) { 
  var secondAttributeArray = []; 
  var currentType = $scope.myObjectArray[i];
  fillSecondAttributeArray($scope, secondAttributeArray, currentType);
 }
Slava Shpitalny
  • 3,965
  • 2
  • 15
  • 22
  • I realized I had a mistake in my code. I have rewritten this line - currentType.secondAttribute = secondAttributeArray; – Tisha Mar 17 '16 at 19:00
  • I would actually prefer directly doing something like - $scope.myObjectArray[i],secondAttribute = secondAttirbuteArray directly instead of using any currentType reference – Tisha Mar 17 '16 at 19:01
  • You can do whatever you want, just do the `utility.getData` in separate function, you can pass it whatever you want. The issue here is that you reference an object outside the `then` statement that is changing as the loop goes. Did you understand my answer? – Slava Shpitalny Mar 17 '16 at 19:32