为了确定用户的会话是否经过身份验证,我需要在加载第一个路由之前向服务器发出$http请求。在加载每个路由之前,身份验证服务会检查用户的状态和路由所需的访问级别,如果用户未针对该路由进行身份验证,则会重定向到登录页面。但是,当应用程序首次加载时,它不了解用户,因此即使他们具有经过身份验证的会话,它也将始终重定向到登录页面。因此,为了解决这个问题,我正在尝试向服务器请求用户状态,作为应用程序初始化的一部分。问题是显然$http调用是异步的,那么在请求完成之前如何停止应用程序运行?
我对 Angular 和前端开发非常陌生,所以我的问题可能是对 javascript 而不是 Angular 的误解。
在路由提供程序中使用resolve
来实现此目的。
这允许您在启动控制器之前等待某些承诺得到解决。
引用文档:
resolve - {Object.=} - 应注入控制器的可选依赖项映射。如果这些依赖项中的任何一个是承诺,则路由器将等待它们全部解析或拒绝一个依赖项,然后再实例化控制器。如果成功解析所有承诺,则会注入已解析承诺的值并触发$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
用sessionCreator
封装所有资源并返回一个承诺。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: '/' });
}]);