3

As most of angular developers know, Resolve property allows to protect access to certain pages.

Here a brief example of snippet code:

.config(['$routeProvider', 'securityAuthorizationProvider',
                function ($routeProvider, securityAuthorizationProvider) {
                      $routeProvider.when('/test', {
                          templateUrl: '/myCorrespondingView.tpl.html',
                          controller: 'MyCorrespondingCtrl',
                          resolve: securityAuthorizationProvider.requireAuthenticatedUser
                      });
                }])

Let's suppose a page containing a link called "Click here to access to protected page" (making a $location.path("/test") under the hood).

Expectations are: when I click on it, make resolve as being rejected and...do not redirect to any other pages than the caller's page.

This causes to...nothing (the simple fact that user can't reach page is enough) but the URL changed to the targeted protected page. => myApp.com/test (why Angular doesn't make this replacement only in case of a successful promise result ?? :(, but this is another question that I've just asked: AngularJS / Changing the URL only when corresponding template's resolve property is solved ).

Then...click again...

It seems that the resolve remains not processed again at all.

Then...click on other link on the application (without full redirect of course), whichever you want in order to change the URL, and reclick on the protected link => Resolve would be well processed again.

Is there an Angular mechanism that checks for the current page URL and the wanted page URL, and avoids to reprocess resolve task if both are the same?

I really want to force the resolve process even if the URL already corresponds to the targeted page one.

**UPDATED ******** From this post: https://stackoverflow.com/a/12429133/985949

Angular watches for a location change (whether it’s accomplished through typing in the location bar, clicking a link or setting the location through $location.path()). When it senses this change, it $broadcasts an event, “$locationChangeSuccess,” and begins the routing process.

It sounds that the check I supposed above is indeed done by $location.path method... Would be great if one can force the evaluation.

Community
  • 1
  • 1
Mik378
  • 21,881
  • 15
  • 82
  • 180
  • I tried to do a simple test if resolve has a reject the url get updated but dont the view – Whisher Oct 29 '13 at 16:41
  • var lastRoute = $route.current; console.log(lastRoute); $scope.$on('$locationChangeSuccess', function(event) { $route.current = lastRoute; }); in my test if the resolve is rejected the controller is not invocake. – Whisher Oct 29 '13 at 17:24
  • @Whisher That's strictly normal: the `$routeChangeError` event is triggered instead. That does not answer to the question ;) What I would like is an elegant way to force `location.path` behavior when the targeted URL is equal to the current one. (whether this is out-of-the-box with angular and forgotten in the official documentation) – Mik378 Oct 29 '13 at 18:11

2 Answers2

3

Angular routes respond to changes in the URL, not to clicks. If the location does not change in the browser angular will not pick it up at all.

It seems what you should do is create a service that listens to "$locationChangeSuccess" and keeps track of the last successful route. Then have another listener on $routeChangeError that resets the location to the last succesful route on a failure. This would prevent you from staying in an inconsistent state where the location does not match your current active route.

Once you do that, clicking on the link again would cause the browser to attempt to change the location again, thus triggering your resolves again.

Daniel Tabuenca
  • 13,147
  • 3
  • 35
  • 38
  • Nice solution is the modification of the last successful route. :) Thanks! Will implement it. – Mik378 Oct 30 '13 at 00:44
0

I found this post confirming the solution of @dtabuenc just above. Here's mine:

angular.module('services.locationChanger', [])
    .service('locationChanger', ['$location', '$route', '$rootScope', function ($location, $route, $rootScope) {

        this.skipReload = function () {
            var lastRoute = $route.current;
            $rootScope.$on('$locationChangeSuccess', function () {
                $route.current = lastRoute;
            });
            return this;
        };

        this.withoutRefresh = function (url, doesReplace) {
            if(doesReplace){
                $location.path(url).replace();
            }
            else {
                $location.path(url || '/');
            }
        };
    }]); 

and any caller within the resolve process part would be:

locationChanger.skipReload().withoutRefresh("/", true);

Works like a charm.

Mik378
  • 21,881
  • 15
  • 82
  • 180
  • This approach works great changing the path without refreshing, but then, any other link on the application stop working. URL change but the content is never refreshed. Anyone with this issue? – adripanico May 30 '16 at 14:52