19

为了确定用户的会话是否经过身份验证,我需要在加载第一个路由之前向服务器发出 $http 请求。在加载每个路由之前,身份验证服务会检查用户的状态和路由所需的访问级别,如果用户未通过该路由的身份验证,它会重定向到登录页面。然而,当应用程序第一次加载时,它不知道用户,所以即使他们有一个经过身份验证的会话,它也会总是重定向到登录页面。因此,为了解决这个问题,我正在尝试向服务器请求用户状态作为应用程序初始化的一部分。问题是显然 $http 调用是异步的,那么我将如何停止应用程序运行直到请求完成?

一般来说,我对 Angular 和前端开发非常陌生,所以我的问题可能是对 javascript 而不是 Angular 的误解。

4

2 回答 2

19

您可以通过resolve在您的 routingProvider 中使用来完成此操作。

这允许您在启动控制器之前等待一些承诺得到解决。

从文档中引用:

resolve - {Object.=} - 一个可选的依赖关系映射,应该注入到控制器中。如果这些依赖项中的任何一个是承诺,路由器将等待它们全部被解决或在控制器被实例化之前被拒绝。如果所有的 Promise 都成功解决,则注入已解决的 Promise 的值并触发 $routeChangeSuccess 事件。

简单的例子

    app.config(['$routeProvider', function($routeProvider) {
    $routeProvider.
        when('/', {templateUrl: 'home.html', controller: 'MyCtrl',resolve: {
            myVar: function($q,$http){
                var deffered = $q.defer();

                    // make your http request here and resolve its promise

                     $http.get('http://example.com/foobar')
                         .then(function(result){
                             deffered.resolve(result);
                          })

                return deffered.promise;
            }
        }}).
        otherwise({redirectTo: '/'});
}]);

然后 myVar 将被注入到您的控制器中,其中包含承诺数据。

避免额外的 DI 参数

您还可以通过返回您将要注入的服务来避免额外的 DI 参数:

app.config(['$routeProvider', function($routeProvider) {
        $routeProvider.
            when('/', {templateUrl: 'home.html', controller: 'MyCtrl',resolve: {
                myService: function($q,$http,myService){
                  var deffered = $q.defer();

                      /*  make your http request here
                      *   then, resolve the deffered's promise with your service.
                      */

                  deffered.resolve(myService),

                  return deffered.promise;
                }
            }}).
            otherwise({redirectTo: '/'});
    }]);

显然,在执行此类操作时,您必须将请求的结果存储在共享服务的任何位置。


看看Angular Docs / routeProvider

我从egghead.io的那个人那里学到了大部分东西

于 2013-10-29T09:57:05.717 回答
2

用 a 封装所有资源sessionCreator并返回一个 Promise。然后到resolve你的控制器,这样你就可以让它没有特定的promise代码。

app.factory('sessionCreator', ['$http', '$q', 'urlApi',

  function ($http, $q, urlApi) {
    var deferred = $q.defer();

    $http.get(urlApi + '/startPoint').success(function(data) {
      // Do what you have to do for initialization.
      deferred.resolve();
    });

    return deferred.promise;
  }

]);

app.factory('Product', ['$resource', 'urlApi', 'sessionCreator',

  function($resource, urlApi, sessionCreator) {
    // encapsulate all yours services with `sessionCreator`
    return sessionCreator.then(function() {
      return $resource(urlApi + '/products', {}, {
        query: {method:'GET', params:{}, isArray: true}
      });
    });
  }

]);

app.config(['$routeProvider', function ($routeProvider) {

  var access = routingConfig.accessLevels;

  $routeProvider
    .when('/product', {
      templateUrl: 'views/products.html', controller: 'ProductCtrl',
      // resolve then in router configuration so you don't have to call `then()` inside your controllers
      resolve: { Product: ['Product', function(Product) { return Product; }] }
    })
    .otherwise({ redirectTo: '/' });
}]);
于 2014-08-29T09:19:06.290 回答