【问题标题】:Force AngularJS service to return data before loading controller强制 AngularJS 服务在加载控制器之前返回数据
【发布时间】:2013-08-30 22:12:14
【问题描述】:

我在 Angular 中有一项服务,它使用我的 API 获取用户信息并将其提供给我的控制器。它是这样设置的:

angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'ngResource', 'infinite-scroll', 'ui.bootstrap', 'ngCookies', 'seo'])
  .service('userInfo', function($http, $cookies){
    $http.get('/api/users/' + $cookies.id).
    success(function(data) {
      var userInfo = data.user[0];

      return userInfo;
    });
  }). // other stuff comes after this

在我的控制器中,我将其包括在内:

function userProfile($scope, $cookies, userInfo, $http, $resource, $routeParams, $rootScope){
    $scope.user = userInfo;
    console.log('user info is')
    console.log(userInfo);

这不会返回任何数据,而如果我将相同的服务函数放在控制器本身中,它会返回很好。我在这里想念什么?以前从未在 Angular 中使用过 DI/Services,所以在某处可能是一个简单的错误。

我需要确保服务在控制器加载之前返回数据。这个怎么实现

【问题讨论】:

  • 你可以像这样简化你的 console.logs:console.log('user info is ', userInfo);
  • @EddieMongeJr 真的吗?不知道,谢谢。

标签: javascript angularjs angularjs-service


【解决方案1】:

您的userInfo 服务必须返回由$http 返回的承诺。然后,该承诺将被注入您的控制器,一旦承诺成功解决,视图将立即更新。


如果您不希望在 userInfo 解析之前呈现视图,您应该在您的路由上设置一个 resolve 属性,并在那里注入您的服务:

$routeProvider.when('/profile', {
    templateUrl: 'profile',
    controller: userProfile,
    resolve: {
         userInfoData: function ($q, userInfo) {
             return userInfo;
         }
    }
});

然后只需将userInfoData 注入到您的控制器中,以代替userInfo 服务。

【讨论】:

  • 我需要这些数据可用于所有控制器/路由,有没有一种特殊的方法可以注入一次,这样我就不必为每条路由执行 20 多次?
  • @Jascination - 我不知道。我认为您只需为您需要的所有路线设置resolve: resolveUserInfo
  • 有趣。我已经尝试过您的解决方案,但它仍然在做同样的事情 - 在数据解析之前加载控制器。由于resolve,我知道这可能不应该是这种情况,我假设这是一个异步/回调问题,因为resolveUserInfo 函数在返回之前没有完成加载数据。
  • @Jascination - 您是否从服务返回了$http 承诺?
  • 有没有机会在不使用路由的情况下完成此任务? stackoverflow.com/q/29889040/4341650
【解决方案2】:

你可以让工厂像这样返回一个承诺:

angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'ngResource', 'infinite-scroll', 'ui.bootstrap', 'ngCookies', 'seo'])
    .service('userInfo', function ($http, $cookies) {
    var promise = $http.get('/api/users/' + $cookies.id).
    success(function (data) {
        var userInfo = data.user[0];
        return userInfo;
    });
    return promise;
}) // other stuff comes after this

在你的控制器中,做

function userProfile($scope, $cookies, userInfo, $http, $resource, $routeParams, $rootScope){
    userInfo.then(function(data){
        $scope.user = data;
    });
}

这可以保证无论何时你使用该服务,它总是同步地为你提供数据,你不必在加载控制器之前加载任何数据。

【讨论】:

  • Promise 可以直接分配给$scope。当 promise 解决时,Angular 会自动更新视图。
  • 请注意,promise 不会在 Angular 1.2+ 中自动展开。
  • 这真的有效吗?我看到 promise 注入的不是响应中的实际数据
【解决方案3】:

您可以像这样将资源对象分配给您的变量 返回 $http.get(url)

【讨论】:

    【解决方案4】:

    我也遇到过同样的问题,我必须使用 $resource 将数据加载到服务中,并将该数据放入控制器 $scope 中。 我不想直接返回承诺,然后在控制器中使用解析器(如@zsong 所写),而是将所有魔法都放入服务中,并使用将承诺直接分配给 $scope 的能力作为@Joseph Silber 指出,这就是我所做的:

    return function($scope){promise.then(function(data){$scope.user = data})};
    

    并像这样在控制器中使用它:

    userInfo($scope);
    

    没有太大的改进,但它让我的控制器语法更清晰,希望它在三年后也能有所帮助!

    【讨论】:

      猜你喜欢
      • 2014-04-08
      • 1970-01-01
      • 2015-11-15
      • 2013-09-13
      • 2016-10-31
      • 2016-03-13
      • 2013-07-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多