Несколько вызовов Ajax при авторизации приложения angular
Приложение имеет два типа ролей: "adam" и "eve". Пользователь может иметь одну или другую роль.
Angular для получения ролей:
app.factory("AuthService",function($http, $q){
var user = undefined;
return {
getRoles : function(){
var deferred = $q.defer();
if(user !== undefined){
deferred.resolve(user.auth);
}else{
$http.get("./rest/auth", {
}).then(function(result){
user = result.data;
deferred.resolve(user.auth);
});
}
return deferred.promise;
}
};
});
Маршрутизация выполняется следующим образом:
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when("/adam", {
templateUrl: 'templates/adam.html',
controller: 'AController'
})
.when("/eve", {
templateUrl: 'templates/eve.html',
controller: 'BController'
})
.when("/", {
resolve: {
load : function($q, $location, AuthService){
var defer = $q.defer();
AuthService.getRoles().then(function(data){
if(data === 'adam'){
$location.path('/adam');
}else{
$location.path('/eve');
}
defer.resolve();
});
return defer.promise;
}
}
})
.otherwise({ redirectTo: '/' });;
}]);
Мне нужно получить роли в контроллере, а также выполнить определенную операцию. Код контроллера:
angular.element(document).ready(function () {
AuthService.getRoles().then(function(data){
// some operation
});
});
При навигации по '/' ajax вызывается дважды, так как функция разрешения и контроллера вызывает AuthService.getRoles(). Как я могу перестроить код так, чтобы ajax вызывался только один раз?
Ответы
Ответ 1
Я бы сменил ваш factory на что-то подобное, чтобы они вступили в одно и то же обещание:
app.factory("AuthService", function ($http, $q) {
var userPromise;
return {
getRoles : function () {
if(!userPromise){
userPromise = $http.get("./rest/auth", {}).then(function(result){
return result.data;
});
}
return userPromise;
}
};
});
Это создает обещание, если оно не установлено, чтобы получить данные. Каждый вызов после этого будет иметь обещание, созданное таким образом, что оно будет просто подключаться к первому и не выполнять последующие вызовы. Причина, по которой он не работает для вас, заключается в том, что ваш пользователь получает только после $http.get, поэтому во второй раз он все еще видит его как undefined.
Ответ 2
Я не понимаю:
Вы не могли бы просто сделать (в своем контроллере):
angular.element(document).ready(function () {
if($route.current !== '/'){
AuthService.getRoles().then(function(data){
// some operation
}
});
});
Это может быть undefined, но вы получите эту идею (возможно, emit- > broadcast- > on даст вам параметры маршрута надежно. Может потребоваться время ожидания $. ($ timeout 0 не грязно в angular он просто устанавливает последнее в очереди).
Ответ 3
вы можете попробовать
Factory
app.factory("AuthService", function ($http, $q) {
var user = undefined;
var authSvc = null;
return function () {
if (!app.isSvcInstance) {
authSvc = null;
this.getRoles = function () {
var deferred = $q.defer();
if (user !== undefined) {
deferred.resolve(user.auth);
} else {
$http.get("./rest/auth", {
}).then(function (result) {
user = result.data;
deferred.resolve(user.auth);
});
}
return deferred.promise;
};
authSvc = this;
return this;
}
return authSvc;
};
});
контроллер
angular.element(document).ready(function () {
app.isSvcInstance = true;
var auth = new AuthService();
auth.getRoles().then(function (data) {
// some operation
});
});
Alternative
app.factory("AuthService", function ($http, $q, $cacheFactory) {
var cacheSvc = $cacheFactory("myCache");
return {
getRoles: function () {
var cacheFac = cacheSvc.get("authCache");
var deferred = $q.defer();
if (!cacheFac || cacheFac.length === 0) {
$http.get("./rest/auth", {
}).then(function (result) {
cacheSvc.put("authCache", result.data);
deferred.resolve(result.data);
});
} else {
deferred.resolve(cacheSvc.get("authCache"));
}
return deferred.promise;
}
};
});
Ответ 4
вы можете проверить функцию $q.all
В основном он объединяет несколько promises в одном