2013-02-18 55 views
6

最初在我的应用程序中,我创建了具有非常基本的$ http调用的控制器,通过从url($ routeParams)获取对象的ID来获取资源。 Ng-repeat正确显示结果。AngularJS ng-repeat与服务中的数据

但是,我注意到在后来的视图(不同的控制器)刷新刷新数据并打破了页面。因此,我在多个控制器上创建了一项服务功能,以检查数据是否可用,并如下作出反应:

1)如果资源已定义,则返回它(无API调用) 2)如果资源没有定义,从url获取id并从API获取。3)如果资源未定义&你不能得到ID,只返回false。

但是,这打破了代码:服务返回数据之前呈现的模板,并且ng-repeat没有更新。代码如下所示:

angular.module('myApp', ['ngCookies']) 
    .config(...) 
    .service('myService', ['$cookies', '$http', function($cookies, $http) { 
     myData = {}; 

     return { 
      getData:function(dataID) { 
       if(myData.name) {return myData); 
       else if (dataID && dataID !== '') { 
        $http.get('/api/data/' + dataID) 
         .success(function(data) { 
          myData = data.object; 
          $cookies.dataID = data.object.id; 
          return myData; 
         } 
       } 
       else { return false; } 
      } 
     } 
    }]); 

function myCtrl($scope, $http, $routeParams, myService) { 
    $scope.data = myService.getData($routeParams.dataID); 

    ... 
} 

这里是模板。它是用jade表示的,而不是尖括号,你只需在括号后面加括号,括号后加内容即可。

h2 My heading 
ul 
    li(ng-repeat='option in data') 
     a(href="#", ng-click='someFuncInCtrl(option.name)') {{ option.name }} 

当控制器做了$ http.get本身,NG-重复工作得很好,因为$范围是在“.success”回调更新。现在有一个服务在稍微延迟后返回数据,“$ scope.data”只是未定义的,ng-repeat列表是空的。

在返回“return myData”之前,我使用了console.log来检查myData,并且myData正在工作,只是没有及时返回,并且无论何时出现任何原因,只要$ scope得到的列表都不会更新数据。

我看着一个使用$ routeProvider的解决方案...但是这使得从URL中获取ID具有挑战性,因为解析对象似乎无法访问$ routeParams。我知道$ scope。$ apply应该可以帮助更新范围,当它被外部函数改变时......但我不知道该把它放在哪里。 SO上的most similar problem没有使用服务。

我想:

$scope.$apply($scope.data = myService.getData($routeParams.dataID)); 

而且

$scope.$apply(function() { 
    $scope.data = myService($routeParams.dataID); 
}); 

这两次我只得到了错误:$已经在进行中消化。

+0

可能想尝试在教程角文档站点的'宁静service'方法。返回一个承诺。 http://docs.angularjs.org/tutorial/step_11 – charlietfl 2013-02-19 00:01:10

回答

11

问题在于您与服务交互的方式。由于您的getData函数可以同时返回同步和/或异步信息,因此不能只使用正常的return(s)。

$http.get('/api/data/' + dataID) 
    .success(function(data) { 
     myData = data.object; 
     $cookies.dataID = data.object.id; 
     return myData; 
    }); 

在上面的代码,因为它会在$http.get成功回调的上下文中执行(不是getData调用堆栈上)将不会从getData返回任何的return

处理同步和异步服务请求的最佳方法是使用promises

getData功能应该是这个样子:

getData:function(dataID) { 
    var deferred = $q.defer(); 
    if(myData.name) { 
     deferred.resolve(myData); 
    } else if (dataID && dataID !== '') { 
     $http.get('/api/data/' + dataID) 
      .success(function(data) { 
       myData = data.object; 
       $cookies.dataID = data.object.id; 
       deferred.resolve(myData); 
       // update angular's scopes 
       $rootScope.$$phase || $rootScope.$apply(); 
      }); 
    } else { 
     deferred.reject(); 
    } 

    return deferred.promise; 
} 

注意:您需要在您的服务注入$rootScope

而且您的控制器上:

function myCtrl($scope, $http, $routeParams, myService) { 
    myService.getData($routeParams.dataID).then(function(data) { 
     // request was successful 
     $scope.data = data;   
    }, function() { 
     // request failed (same as your 'return false') 
     $scope.data = undefined; 
    }); 
} 
+0

非常感谢。还将$ q注入服务。像魅力一样工作。 – ansorensen 2013-02-19 06:15:26

+0

谢谢,谢谢!我需要注入$ rootScope到我的服务来更新角度的范围后解决我的延期(通过$ rootScope。$$阶段|| $ rootScope。$ apply()) – remi 2013-07-31 05:29:12