2

I'm trying to write a factory that gets data from two sources and uses one source to expand the data in the other object.

app.factory('information', ['$http', '$q', 'players', 'matches', function($http, $q, players, matches) {
    return {
        // Returns all matches and players including extra parsing
        get: function() {
            return players.get().success(function(data) {
                players = data;

                matches.get().success(function(data) {
                    matches = data;

                    for ( match in matches ) {
                        matches[match].a_player1 = players.filter(function(player) { return player.username == matches[match].a_player1 })[0];
                        matches[match].a_player2 = players.filter(function(player) { return player.username == matches[match].a_player2 })[0];
                        matches[match].b_player1 = players.filter(function(player) { return player.username == matches[match].b_player1 })[0];
                        matches[match].b_player2 = players.filter(function(player) { return player.username == matches[match].b_player2 })[0];
                        console.log(matches)
                    }

                    return matches;
                });
            });
        },
    }
}]);

Both matches.get() and players.get() are simple GETrequests to an API like so:

app.factory('players', function($http) {
    return {
        get: function() {
            return $http({
                method: 'GET',
                url: '/players',
            });
        },
    }
});

But the above code (of course) returns the players object while I want it to return the matches object after it gets combined with the players object.

Any tips on how to do this?

2 Answers 2

5

That function won't return anything since you can't directly return a value from an async operation, either return the promise or use a callback. But I think what you're looking for is $q.all:

return {
        // Returns all matches and players including extra parsing
        getEverything: function() {

        var getPlayers= $http({
            method: 'GET',
            url: '/players',
        });
        var getMatches= $http({
            method: 'GET',
            url: '/matches',
        });

           return $q.all([getPlayers,getMatches]);
        }
}

Usage:

getEverything().then(function(data){
   var players=data[0].data;
   var matches=data[1].data;
})

EDIT:

Irrelevant, but to move this back in the factory:

getEverything: function() {
            var getPlayers= $http({
                method: 'GET',
                url: '/players',
            });
            var getMatches= $http({
                method: 'GET',
                url: '/matches',
            });
            return $q.all([getPlayers,getMatches]);
},
getEverythingMapped:function(){
 var deferred = $q.defer();
 this.getEverything().then(function(data){
       var players=data[0].data;
       var matches=data[1].data;
//do as many loops on either result set as you like
                for ( match in matches ) {
                    matches[match].a_player1 = players.filter(function(player) { return   player.username == matches[match].a_player1 })[0];
                    matches[match].a_player2 = players.filter(function(player) { return player.username == matches[match].a_player2 })[0];
                    matches[match].b_player1 = players.filter(function(player) { return player.username == matches[match].b_player1 })[0];
                    matches[match].b_player2 = players.filter(function(player) { return player.username == matches[match].b_player2 })[0];
                    console.log(matches)
//use of a promise here allows us top use this method using -then, we need to so this since we're
//waiting for the result of an async server call before we can loop through players and matches
                     deferred.resolve(matches);
                }


 }
}

Now you would use the above method like this in your controller:

information.getEverythingMapped().then(function(matches){
 console.log(matches);
})
Sign up to request clarification or add additional context in comments.

6 Comments

But then where would I parse my data (the for in loop)?
Anywhere. What I wrote is just a blueprint, you could put the for loop after the service call, after var matches=data[1].data;
In this particular example, since there is no dependency on two GET calls, $q is a better option. Nested $http when you have dependencies.
I don't think you understood my question. In order to parse the matches object I need to be sure that the $http request already finished because I need the players object for additional information and I want to parse it inside the factory because I want to be able to use it in multiple controllers.
@CasCornelissen I understood your question :) You have both those result sets available after var players=data[0].data;var matches=data[1].data; So you can do whatever you like with the. You can also move this code back into your factory, whats the problem????
|
2

As per the docs for $http, this service returns a promise. So no need for the $q service in this case it can be simply written like this:

app.factory('information', ['$http', 'players', 'matches', function($http, players, matches) {
    return {
        // Returns all matches and players including extra parsing
        get: function(callback) {
            players.get().then(function(playersData) {
                matches.get().then(function(matchesData) {
                    matches = matchesData;
                    players = playersData;
                    for ( match in matches ) {
                        matches[match].a_player1 = players.filter(function(player) { return player.username == matches[match].a_player1 })[0];
                        matches[match].a_player2 = players.filter(function(player) { return player.username == matches[match].a_player2 })[0];
                        matches[match].b_player1 = players.filter(function(player) { return player.username == matches[match].b_player1 })[0];
                        matches[match].b_player2 = players.filter(function(player) { return player.username == matches[match].b_player2 })[0];
                        console.log(matches)
                    }
                    callback(matches);
                });
            });
        },
    }
}]);

and in the controller call information like this:

information.get(function(data){
    console.log(data);
});

7 Comments

I tried that already but it keeps returning a TypeError: undefined is not a function
Error maybe in something else then, have you put consoles for matches and players and checked the values coming?
It's definitely the get function and I think it happens because it doesn't return anything directly. I can't call it like information.get().succes(function() { ... } ) either, because it doesn't return a promise. And calling console.log(information.get()) returns undefined, which matches my hypothesis.
@CasCornelissen: updated the code to have a callback inorder to return the matches when everything is done. This callback can be used as shown in the controller which is consuming the information factory
Very hard to understand why you getting this error as everything appears to be fine. Can you come up with a plunkr for this problem. You can create JSON files in order to replicate your factory calls for matches and players
|

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.