Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple AngularJS get requests into one model

Is there a way to call an unknown amount of API calls to a URL via the get() function in AngularJS and add those all into a model ($scope variable). What I've done thus far is the following:

if(theUIDS != "") {
    var myDropbox = [];

    for(i = 0; i < theUIDS.length; i++) {
        var temp = {};

        temp.uid = theUIDS[i];

        $http({ url: '/dropbox/accounts/get', method: 'GET', params: { uid: theUIDS[i] }}).success(function(acctData) {
            temp.accountInfo = acctData;
        });

        $http({ url: '/dropbox/files/get', method: 'GET', params: { uid: theUIDS[i] }}).success(function(fileData) {
            temp.files = fileData;
        });

        myDropbox.push(temp);
    }

    $scope.dropboxAccounts = myDropbox;
}

I check if there are any UID's and for each one I create a temp object which is populated with a uid, then an accountInfo object, and then a files object. After I set up my temp object, I push it onto the myDropbox array. Once the loop has finished, I set the dropboxAccounts model to the myDropbox variable in $scope. I'm new to Angular, but I'm pretty sure this is at least the right idea. Luckily I'm getting the following data in correct order:

{"uid":"332879"}
{"uid":"155478421",
    "accountInfo":{
        "country":"US",
        "display_name":"Patrick Cason",
        "name":"Second Dropbox",
        "quota_normal":1174504,
        "quota_shared":0,
        "quota_total":2147483648,
        "referral_link":"https://www.dropbox.com/referrals/NTE1NTQ3ODQyMTk?src=app9-203957",
        "uid":155478421},
    "files":[{
        "created_at":"2013-04-17T15:13:46Z",
        "directory":true,
        "dropbox_user_id":26,
        "fileType":"Folder",
        "id":198,
        "name":"Photos",
        "path":"/Photos",
        "rev":"10edb44f9",
        "size":"-",
        "updated_at":"2013-04-17T15:13:46Z"}]
}

The strange thing is that only one of my UID's gets updated. I know that the loop is correctly going through because I have two UID's and if I alert at the beginning the loop I get two loops. The reason I think the second isn't being populated is because the push statement isn't waiting for both of the promises to go through. How can I ensure that I wait for each of the AJAX calls to finish before assigning myDropbox to the $scope variable?

like image 475
cereallarceny Avatar asked Apr 17 '13 15:04

cereallarceny


1 Answers

Introduction

I'm pretty new to AngularJS, so this solution is very much so a work-in-progress. I figure that since I've struggled through learning more about it that other people may be in the same position as well. With that said, I'm going to not only post my answer, but also explain my thinking behind the code. I'd love to get any feedback if anyone feels the answer could be improved any.

Final Code

Here's the code I used to get everything working:

var app = angular.module('myApp', []);

app.controller('DropboxCtrl', function($scope, dropbox) {
    $scope.dropboxAccounts = dropbox.getAccounts();
    $scope.dropboxFiles = dropbox.getFiles();
});

app.factory('dropbox', function($http, $q) {
    var theUIDS = [12345,67890];

    return {
        getAccounts: function() {
            var promises = [];

            for(i = 0; i < theUIDS.length; i++) {
                promises.push($http({
                    url: '/dropbox/accounts/get', 
                    method: "GET",
                    params: { uid: theUIDS[i] }
                }));
            }

            return $q.all(promises);
        },
        getFiles: function() {
            var promises = [];

            for(i = 0; i < theUIDS.length; i++) {
                promises.push($http({
                    url: '/dropbox/files/get', 
                    method: "GET",
                    params: { uid: theUIDS[i] }
                }));
            }

            return $q.all(promises);
        }
    }
});

Basic Algorithm

We start by declaring a module myApp and saving it in a variable app... notice the empty array we're passing which would normally be a parameter for any further requirements which may or may not be inherited from other modules.

After our module is declared we need to create a corresponding controller which will be a gateway for all interactions to take place. In this case we need access to the $scope variable which is relative to our controller (not relative to the app itself). We also declare what factory this controller is related to, in my case it's dropbox (we'll get to factories in a moment). Inside of this controller we assign two models to $scope: dropboxAccounts and dropboxFiles. Note that my original desire was to have one model within my AngularJS app. While this is possible... I opted against it because I found it difficult to differentiate my two types of JSON returns apart. One returns account metadata and the other returns an array of files of that account. I would have liked to have all these under one model and be sorted by a uid parameter, but found this to be impossible to do without changing what JSON my RESTful endpoints output. In the end, I opted for two separate models so I can work with them easier (until I find a way to combine them according to one common parameter).

Lastly, we create a factory which stores my AJAX functions (using $http for the actual AJAX call, and $q for handling the promises). I have two functions: (which remember are called from my controller) getAccounts and getFiles. Each of them has an array called promises which will store the promises of my $http calls. I run through these calls in a for-loop which will look at each of my items in theUIDS, which is used in my AJAX call, and is then pushed onto the promises array. At the end we have our $q which will wait until all the AJAX calls in the promises array has finished successfully before returning all that data in one big promise back to our controller and assigning it to $scope.

What I Learned

AngularJS is really tough. This particular issue has taken me two days of debugging and trying again and again. I have been told that while the learning curve to this front-end MVC framework is pretty steep, the payoff is well worth it. I suppose we shall see...

Resources

  • AngularJS API
  • Factories and Services comparison
  • Good use of AngularJS's all method
  • Beautiful explanation of AJAX promises both in jQuery and AngularJS
like image 71
cereallarceny Avatar answered Oct 18 '22 03:10

cereallarceny