Angularjs 角度视图在http拦截器之后不更新
我正在控制器中使用promise在Angularjs 角度视图在http拦截器之后不更新,angularjs,angularjs-scope,angular-ui-router,angular-services,angular-http-interceptors,Angularjs,Angularjs Scope,Angular Ui Router,Angular Services,Angular Http Interceptors,我正在控制器中使用promise在$http请求后呈现视图。除了http拦截器在401错误期间介入之外,其他一切都正常工作。当这种情况发生时,这就是我面临的问题: http拦截器从api中获取401错误,补充道 被拒绝的查询将被缓冲并显示登录模式 登录成功后,排队的api查询 再次尝试401 before,api返回请求的数据 成功 然而,即使从api返回数据, 角度视图不会更新。视图仅在更新后更新 手动刷新该状态 这些是我的代码: scope.$on('event:auth-loginRequ
$http
请求后呈现视图。除了http拦截器在401错误期间介入之外,其他一切都正常工作。当这种情况发生时,这就是我面临的问题:
scope.$on('event:auth-loginRequired', function() {
LoginModalService.openLoginModal();
console.log('login needed');
});
scope.$on('event:auth-loginCancelled', function() {
$state.go('index');
});
1)http侦听器:
scope.$on('event:auth-loginRequired', function() {
LoginModalService.openLoginModal();
console.log('login needed');
});
scope.$on('event:auth-loginCancelled', function() {
$state.go('index');
});
我在这里使用的是httpauth拦截器
$httpProvider.interceptors.push(['$rootScope', '$q', 'httpBuffer', function($rootScope, $q, httpBuffer) {
return {
responseError: function(rejection) {
if (!rejection.config.ignoreAuthModule) {
var rejectionReasons = ['token_not_provided', 'token_expired', 'token_absent', 'token_invalid'];
angular.forEach(rejectionReasons, function(value, key) {
if(rejection.data.error === value) {
var deferred = $q.defer();
httpBuffer.append(rejection.config, deferred);
$rootScope.$broadcast('event:auth-loginRequired', rejection);
return deferred.promise;
}
})
}
// otherwise, default behaviour
return $q.reject(rejection);
}
};
}]);
2)http侦听器监视:
scope.$on('event:auth-loginRequired', function() {
LoginModalService.openLoginModal();
console.log('login needed');
});
scope.$on('event:auth-loginCancelled', function() {
$state.go('index');
});
3)控制器:
.controller('FetchData', ['$scope', 'DataService',
function($scope, DataService) {
DataService.fetchNamesList()
.success(function(names) {
$scope.namesList = names;
}).error(function(error) {
// The login modal should show if auth error occurs
});
}])
这里,DataService.fetchNamesList()
从api发出get请求
如果针对上述内容触发了身份验证拦截器,我可以看到在成功登录后再次尝试$http$\u GET
,但$scope.namesList
未在视图中更新
到目前为止我的想法:
scope.$on('event:auth-loginRequired', function() {
LoginModalService.openLoginModal();
console.log('login needed');
});
scope.$on('event:auth-loginCancelled', function() {
$state.go('index');
});
1) 我正在考虑为上述内容添加一个额外的$watch
,以便它在http拦截器之后工作。我想到了这一点,然后我放弃了这个选项,因为如果我在一个页面中有多个get请求(如仪表板),那么观察每个请求可能会过火
2) 登录后手动刷新ui路由器状态,如下所示。这是可行的,但当视图涉及表单提交时,完成的表单将在状态重新加载后重置,这没有帮助:
$state.go($state.current, {}, {reload: true});
所以我确定如何解决这个问题。有人能带我到这里吗
编辑:
在@ChrisFoster在评论中提出建议后,我将return deferred.promise
移至angular.forEach
之外,并略微更改了forEach检查。这似乎可以在登录后正确更新视图。但是,现在模式会显示每个错误,而不仅仅是拒绝原因中列出的错误:
$httpProvider.interceptors.push(['$rootScope', '$q', 'httpBuffer', function($rootScope, $q, httpBuffer) {
return {
responseError: function(rejection) {
if (!rejection.config.ignoreAuthModule) {
var rejectionReasons = ['token_not_provided', 'token_expired', 'token_absent', 'token_invalid'];
// Loop through each rejection reason and redirect
angular.forEach(rejectionReasons, function(value, key) {
if(!(rejection.data.error === value)) {
return $q.reject(rejection);
}
});
var deferred = $q.defer();
httpBuffer.append(rejection.config, deferred);
$rootScope.$broadcast('event:auth-loginRequired', rejection);
return deferred.promise;
}
// otherwise, default behaviour
return $q.reject(rejection);
}
};
}]);
这就是我目前正在使用的有效方法: 1) 删除了
angular.forEach
,并将其替换为简单的if
语句。因为我只检查了几个条件,if
是我认为的一个不错的选择
2) 我在if
语句中添加了deferred.promise
,之后一切正常。该视图在登录后得到更新,控制器可以继续解析从api返回的数据
这是我的代码:
$httpProvider.interceptors.push(['$rootScope', '$q', 'httpBuffer',
function($rootScope, $q, httpBuffer) {
return {
responseError: function(rejection) {
if (!rejection.config.ignoreAuthModule) {
var rejectionReasons = ['token_not_provided', 'token_expired', 'token_absent', 'token_invalid'];
// Loop through each rejection reason and redirect
if (
rejection.data.error === 'token_not_provided' ||
rejection.data.error === 'token_expired' ||
rejection.data.error === 'token_absent' ||
rejection.data.error === 'token_invalid'
)
{
var deferred = $q.defer();
httpBuffer.append(rejection.config, deferred);
$rootScope.$broadcast('event:auth-loginRequired', rejection);
return deferred.promise;
}
}
// otherwise, default behaviour
return $q.reject(rejection);
}
};
}]);
感谢@ChrisFoster指出了错误:
您的返回延迟。承诺在angular.forEach中。这意味着
它返回到函数内部,而不是承诺处理程序。
您需要将其分配给forEach之外的变量
函数并以这种方式返回
很高兴看到你的答案有效。如果愿意,您仍然可以使用
angular.forEach
,下面是一个示例:
$httpProvider.interceptors.push(['$rootScope', '$q', 'httpBuffer', function($rootScope, $q, httpBuffer) {
return {
responseError: function(rejection) {
var loginRequired = false;
var rejectionReasons = [
'token_not_provided', 'token_expired',
'token_absent', 'token_invalid'
];
// Loop through each rejection reason
angular.forEach(rejectionReasons, function(value, key) {
if (!(rejection.data.error === value)) {
// Set loginRequired, and check this later
// We *can't* return here because we are inside a function :)
loginRequired = true;
}
});
// Create a promise
var deferred = $q.defer();
if (loginRequired && !rejection.config.ignoreAuthModule) {
// Display a login module and queue a retry request
httpBuffer.append(rejection.config, deferred);
$rootScope.$broadcast('event:auth-loginRequired', rejection);
} else {
// Not a auth error, or ignoreAuthModule is enabled
// Therefore immediately reject the promise with the fail value
deferred.reject(rejection);
}
// Return the promise
return deferred.promise;
}
};
}]);
forEach
出现问题的原因是您将函数作为参数传递给了forEach
。当您return
在其中时,您将在forEach
函数中返回该值,而不是在HTTP侦听器函数中返回该值。因此,您有三种选择:
进行循环
if
条件语句您的示例使用的是第二种方法,但是如果您仍然想使用
angular.forEach
my code上面是第三种方法的演示。第一种方法也是可能的,但不太常见,也有点混乱。您的返回延迟。promise
位于angular.forEach
中。这意味着它将返回到该函数内部,而不是承诺处理程序。您需要将其分配给forEach
函数之外的变量,并以这种方式返回。我不确定这是否是你的全部问题,但这是问题的一部分:)@ChrisFoster我想你是对的。当我在forEach
循环之外删除return deferred.promise
时,视图会很好地更新。所以你发现了我的错误。然而,我仍然停留在如何修复它的权利。我的意思是,我稍微更改了foreach,这样它就可以检查不相等,如果不继续使用deliver.promise
,就会返回默认行为。但是,当我将deferred.promise
移动到foreach外部时,模式显示为每400个错误,而不是我在RejectionReasures下列出的错误。延迟和承诺的事情让我很困惑,我不知道是非。我用错误的尝试更新了我的问题。你能帮我吗?仍然坚持下去:(@ChrisFoster我终于让它工作了。我必须阅读基础知识,花一些时间学习promise
和angular forEach
。后来我意识到我错了。我现在使用了一个简单的if
语句并处理了延迟。promise
。这似乎有效。我补充了这一点作为答案由于这是我目前正在使用的解决方案。如果您觉得这可以更有效地完成,请务必告诉我。非常感谢您的评论。您50字的评论让我获得了丰富的知识。:)很高兴你能让它工作!我很高兴你能弄清楚到底发生了什么。你目前的答案非常好,但如果你还想知道如何使用angular.forEach
,请查看我在下面添加的答案:)完美。这有助于成堆的sinc