在AngularJS中的嵌套异步调用中交换数据

时间:2014-07-17 09:55:22

标签: angularjs rest tags promise

我是AngularJS世界的新手,我面临着一个有趣的问题:

我创建了一个Angular工厂服务,它作为我正在调用的REST服务的服务代理。 我的服务代理如下所示:

angular.module('myApp').factory('myService', ['$http', function($http) {

    var baseAddr = "http://myservice.com";
    var token = "secure_identifier";

    var MyService = {
        doRequest: function(method, path, token, postData) {
            return $http({method: method, url: baseAddr+path, headers: {....}, data:postData });
        }
    }

    return {

        GetGroupUsers: function( id)
        {
            return MyService.doRequest('GET', '/api/groupusers/'+id+'.json', token, null);
        },
        GetUser: function( id)
        {
            return MyService.doRequest('GET', '/api/users/'+id+'.json', token, null);
        }
    }
}]);

因此GetGroupUsers返回给定组中的 userID-s 数组,GetUser返回属性 指定的成员(例如电子邮件地址,全名,用户名,出生日期)。 我想要的是查询一个组,(获取该组中的userid-s)并将用户的名称附加到数组项 在GetUser(userid)方法的帮助下。 我有一个控制器,我通过我的代理服务查询此服务。这是控制器的相关部分:

//...
MyService.GetGroupUsers(GroupId).then(function(userlist)
{
    //userlist is an array of a complex object that consists of userId-s and groupId-s
    //Suppose that it looks like this:
    // [ {uid: 1, groupId: 1}, {uid: 2, groupId: 1}, {uid: 3, groupId: 1},...,.. ]
    $scope.groups = userlist.data;

    //but i need to attach for every item in the array the name of the selected user
    // [ {uid: 1, groupId: 1,username: 'Alga Rithem'}, {uid: 2, groupId: 1, username:'Anna Nimmity'}, {uid: 3, groupId: 1, username:'Anna Conda'},...,.. ]

    //So I iterate over the userlist
    for (var i = 0; i < userlist.data.length; i++)
    {
        MyService.GetUser(userlist.data[i].uid).
            then(function(user)
            {
                //And here is the problem I'm facing with:
                //The value of variable "i" becomes obsolate, because GetUser call is async to the for-loop
                // when the "then" "callback" executes, the loop may has been finished already!
                //So I dont really know, where to put the value I've just received
                //I need that value of i, what it was when i called the service!               
                $scope.groups[i].name = user.data.name;  //So this is WRONG!
            });
    }
});

//...

我用一点点黑客解决了这个问题: 我使用一个参数将GetUser(用户名)的参数列表扩展到GetUser(用户名,标记)。在这个标签中我可以放任何我想要的东西 在回调中检索。

所以我稍微修改了我的代码:

//Service proxy

doRequest: function(method, path, token, postData,tag) {
            return $http({method: method, url: baseAddr+path, headers: {....}, data:postData });
        }
//...

GetUser: function( id, tag)
        {
            return MyService.doRequest('GET', '/api/users/'+id+'.json', token, null,tag);
        }

现在我可以在控制器中检索I的有效过去值:

修改后的控制器代码:

//...

MyService.GetGroupUsers(GroupId).then(function(userlist)
{    
    $scope.groups = userlist.data;

    for (var i = 0; i < userlist.data.length; i++)
    {
        MyService.GetUser(adat.data[i].uid).
            then(function(user)
            {                
                $scope.groups[parseInt(user.config.tag)].name = user.data.name;  //This Works fine!
            });
    }
});

我的问题是:此解决方案在技术上是否正确?对于这样的问题,最佳做法是什么? AngularJS有这个工具吗?

ps:在这种情况下,修改REST服务API以返回用户名也不是解决方案。

提前致谢

1 个答案:

答案 0 :(得分:0)

您可以使用.forEach循环而不是关闭for的{​​{1}}循环:

i

或者您可以使用 userlist.data.forEach(function(user, i){ MyService.GetUser(user.uid). then(function(user) { $scope.groups[i].name = user.data.name; //So this is WRONG! }); } 创建地图并使用.map一次性进行所有更新:

$q.all

虽然实际和实际的解决方案不是 $q.all(userlist.data.map(function(user){ return MyService.GetUser(user.uid)) }).then(function(users){ // assign to scope, users is an array here and you can use indices }); 调用n个用户,而是创建一个方法,在服务器上接受多个UID并立即为它们提取所有数据,因为它会加载系统更少,执行速度更快,因为它不会进行n往返和http请求。