2

So, I'm experimenting with AngularJS, and, as an exercise, figured I would make a simple application using the Steam API. I have made a simple Spring Boot Rest service, which provides a reverse proxy service for the Steam API, in such a way that certain calls can be forwarded. At this time there are two actions:

/user/ provides a list of steam id's. /user/:id/games provides the output of the following api: http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=MY_STEAM_KEY&steamid=STEAM_ID&format=json

which returns an answer in the following format:

{  
   "response":{  
      "game_count":3,
      "games":[  
         {  
            "appid":70000,
            "playtime_forever":0
         },
         {  
            "appid":550,
            "playtime_forever":0
         },
         {  
            "appid":274900,
            "playtime_forever":0
         }
      ]
   }
}

What I want to achieve is to extract the games array from this json object, and append it to the correct user. And I want to do this for all users. I have achieved something close to what I want using the $resource object, by defining the following factories:

angular.module("SAM.Resources", [])
    .factory("UserList", ["$resource",
        function ($resource) {
            return $resource('/user');
        }])

    .factory("GamesList", ["$resource",
        function ($resource) {
            return $resource('/user/:id/games', {
                id: '@id'
            });
        }
    ]);

And then in my controller use the following:

UserList.query(function(response){
    $scope.users = response ? response : [];
    for(index=0; index < $scope.users.length; ++index){
        user = $scope.users[index];
        $scope.users[index].games = GamesList.get({id:user.id});
    }
});

This is close to what I want, however, it returns something of the format:

  {
    "id": "76561198119953061",
    "name": "Yuri",
    "games": {
      "response": {
        "game_count": 3,
        "games": [
          {
            "appid": 70000,
            "playtime_forever": 0
          },
          {
            "appid": 550,
            "playtime_forever": 0
          },
          {
            "appid": 274900,
            "playtime_forever": 0
          }
        ]
      }
    }
  }

And I don't want the games.response.games construction. I have tried to change it to:

$scope.users[index].games = GamesList.get({id:user.id}).response.games;

which fails, seems logical, as it is a promise, and doesn't immediately contain the response object.

I've also tried to use something like

GamesList.get({id:user.id}), function(response){
 angular.extend(user, response);
});

Which does indeed append the response to the user object, only the user object is always the last value in the array by the time the promise resolves.

So basically my question comes down to: How can I extend my User object with the Games list?

2
  • "which fails, seems logical, as it is a promise, and doesn't immediately contain the response object." - Except that that code is in the success callback. response should be filled there... Commented Nov 17, 2015 at 8:12
  • 1
    @Cerbrus response is filled correctly, but user is not Commented Nov 17, 2015 at 8:13

2 Answers 2

2

You need to change your code around a bit:

UserList.query(function(response){
    $scope.users = response ? response : [];
    for(index=0; index < $scope.users.length; ++index){
        user = $scope.users[index];

        (function(index, id){
            GamesList.get({id: id}, function(response){ // Get the games from the response
                $scope.users[index].games = response.response.games;
            }));
        })(index, user.id)
    }
});

In the for loop, user keeps changing value. By the time the first GameList.get has a value returned, your loop will be at the last user already.

Wrapping that in an IIFE separates those variables in a separate scope.

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

4 Comments

Notice that you need to use response.response., since the response from the server contains an response object that contains the games
Thanks, marked your answer as the answer, because of the IIFE.
Thanks, much appreciated!
nice, clean approach!
1
for(index=0; index < $scope.users.length; ++index){
    user = $scope.users[index];
    $scope.users[index].games = GamesList.get({id:user.id}, function(response){
        angular.extend(user, response);
    }));
}

When you do that, the user variable will change at every step. But the anonymous callback will be executed later. So only the last user is used.

You can fix that by using an anonymous function as a scope with forEach :

$scope.users.forEach(function(user) {
    $scope.users[index].games = GamesList.get({id:user.id}, function(response){
        angular.extend(user, response);
    }));
});

If you want to avoid the user.games.response.games, you need to merge the objects in a different way.

$scope.users.forEach(function(user) {
    $scope.users[index].games = GamesList.get({id:user.id}, function(response){
        user.games = response.games;
        user.games_count = response.games_count;
    }));
});

5 Comments

Ah that at least solves part of my problem, thanks :)! So, how can I make sure the response.games part is removed?
You can use delete response.games; if you want to remove a property from an object.
Sorry, to clarify: After the promise resolves, the object contains something of the format: user.games.response.games, which I want to simplify to user.games.
Ah I see, thanks :). It's actually response.response.games, but it was clear enough :) Thanks!
Thanks again for your help. I can only mark 1 answer as the correct one, so I gave an upvote.

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.