Closed bbshopadmin closed 5 years ago
Hi,
I am sorry, but this question does not seem to address angular-http-auth
, but some route-handling library of your choice, does it?
More than that, I strongly advise against any kind of redirection in response to event:auth-loginRequired
, because this can destroy the user's context. Making everything invisible excluding the login form is much simpler and does not reset anything, like state of forms, selected options or what-else user was doing. See the demo app for reference.
You're right it has only indirectly to do with angular-http-auth. But i think it's a standard scenario. I have a normal route with a promise which has to be authenticated. When i change to that route i show a login form popup which is cancelable. I have no redirect in there. The problem is that the location has already changed before the route with the promise is resolved. Somehow i have to manually reject that promise when the user clicks cancel on the login popup. Is there an example how to do all that?
I have never used default AngularJS routes with a resolve
route declaration, so I cannot tell. Maybe you could provide some example code, so we could pin the problem to something tangible?
Ok, let's say i'm on '/home' view and go to '/item', which requests server data via ItemResource in which the user must be authenticated, therefor the login form shows up.
$routeProvider
.when('/item', {
templateUrl: 'item.tpl.html',
controller: 'ItemController',
resolve: {
data: ['ItemResource', function(ItemResource){
return ItemResource.get().$promise;
}]
}
});
The login form popup is cancelable and fires a loginCancelled event. Till here it's working fine. Now i've to reject the routes resolve/promise somehow:
$scope.$on('event:auth-loginCancelled', function() {
// reject ItemResource.get().$promise;
});
In case of loginCancelled i've than to change the location/url back to previous location '/home', due to location is now '/item' and gets never resolved.
OK, so I don't know much about resolve
of route providers and also never used "Resource" module, but let me guess, correct me if I am wrong.
The resolve
is an object with keys as identifiers for injection point and values which may evaluate to promises, right? In your case, routing infrastructure waits for data
's promise to resolve before creating ItemController
? Also, while waiting for data
, if the promise blows with an exception, you will actually never reach that "/item" destination... and this is what you want?
In that case let's move to part 2, this is the return ItemResource.get().$promise
. I guess, that thing invokes HTTP request, that request returns with STATUS=401, then angular-http-auth
comes into play. It captures the response, so the ItemResource.get().$promise
does neither resolve nor reject...
OK, now I get it. There is one more thing before you reach this:
$scope.$on('event:auth-loginCancelled', function() {
// reject ItemResource.get().$promise;
});
You had manually to invoke the authService.loginCancelled(data, reason)
(then, and only then you will end up in the scope event from above snippet), see the source code. If you provide any reason
, the buffered promises will be rejected. If you provide no reason
, the promises will be discarded.
So, to answer your question, just provide a reason
parameter and you will get your reject.
Thank you, i missed reason
, i'm now getting the $routeChangeError
event.
I've only left that wrong $location
issue and that the rejected route remains as history entry. I couldn't find something useful so far.
I can't find a solution regarding the wrong $location
and history issues.
How would you handle a cancelable login popup?
Did you try the $location.path('/').replace()
thing?
Yes, but nothing happens. The history entry doesn't get removed and the location looks still wrong. Respectively replace()
works on the next location change. I'm stuck on $routeChangeError
.
$rootScope.$on("$routeChangeError", function (event, current, previous, rejection) {
$location.replace();
$location.path(previous.$$route.originalPath);
});
This would reload '/home', but i'm already/still on '/home' because '/item' was rejected and never rendered. I don't want that reload.
I'm thinking about:
'/home' > '/item' (rejected, because of cancelled auth) > replace()
> '/error'
The history would now contain: '/home' > '/error'
Perhaps somthing like this would reasonable:
'/home' > '/item' (rejected, because of cancelled auth) > replace()
> '/error' > replace()
To get rid of that '/error' page too.
I think you can get much better support for $route and $location on AngularJS project mailing list, I really can't help you much on this subject.
Ok, thank you. But, i think it could be intresting for other users of your lib too. I can't imagine i'm the only one who ever tried that combination.
Let us know if you find the solution.
Perhaps you can use
$route.reload()
@feliksg Thank you. In the docs it says reload() "Causes $route service to reload the current route even if $location hasn't changed.". I only want to change the current $location url back to the previous one without any reload. Due to $route listens to $location changes i don't think i can do that. For now i switched from the login popup to a login view.
Any progress on this?
Hi, I was recently faced with the same problem. My solution is pretty simple:
app.run([ '$rootScope', '$location', function ($rootScope,$location, auth) {
$rootScope.previousLocation = '/';
$rootScope.currentLocation = '/';
/** Simply switch the Locations and save the new to current */
$rootScope.$on("$locationChangeStart", function (e, currentLocation, previousLocation) {
$rootScope.previousLocation = $rootScope.currentLocation;
$rootScope.currentLocation = $location.path();
});
/** Switch back */
$rootScope.$on("event:auth-loginCancelled", function (data) {
$location.path($rootScope.previousLocation);
});
}]);
I hope it helps :)
This is useful solution and I may use it. But I might expend it to something that keeps track of entire history of routes, providing better functionality for a back/forward buttons. Yes I know browsers can do this, but on mobile I'd prefer to render my own buttons (or rather map it to drag left/right).
Hi @wcyrek-comrise the history remains intact.
I think it all goes too far. My experience is that we should never tinker with location on authentication events. This module works best when used as in demo:
The only exception to this rule is when the newly logged user is not the same as previously, so we discard all the cached requests and everything and redirect to a landing page.
When event:auth-loginRequired event is fired on a route change promise, the location has already changed to the new route. How can i revert that location change on the auth-loginCancelled event?