Question

Im using Grails server side and Angular client side.

If the user is not allowed to access a page I redirect with Grails using response.sendError(404)

It is working but PrivateProfileController is calling before the redirection and it shows the template private.html for 1 seconds then redirecting to the template 404.html.

Is there a way to avoid displaying private.html before redirecting ?

Thank you

Grails controller's method

 def privateProfile(){
     if(NOT_AUTHORIZED){
         return response.sendError(404)
     }
 }

Angular

app.config( ['$routeProvider', '$locationProvider', 
             '$tooltipProvider', '$compileProvider', '$httpProvider',
    function($routeProvider, $locationProvider, $tooltipProvider, 
             $compileProvider, $httpProvider) {
        $locationProvider.html5Mode(true) ;
        $routeProvider
          .when('/:username/private', {
             templateUrl: '/js/angular/app/userprofile/templates/private.html',
             controller: 'PrivateProfileController'
          })
            .when('/404', {
                templateUrl: '/js/angular/app/error/404.html' , 
                controller: 'HTTPErrorController'
            })
            .otherwise({

            });

            $httpProvider.responseInterceptors.push(
                ['$location', '$q', function ($location, $q) {
                    function success(response) {
                        return response;
                    }

                    function error(response) {
                        if (response.status === 404) {
                            $location.path('/404');
                            return $q.reject(response);
                        }
                        else {
                            return $q.reject(response);
                        }
                    }

                    return function (promise) {
                        return promise.then(success, error);
                    }
            }]);
    }

    ]).run(function ($rootScope) {
        $rootScope.$on('$locationChangeStart',
             function(evt, absNewUrl, absOldUrl) {
                //console.log('Start : old', absOldUrl, 'new ',absNewUrl );
        });
        $rootScope.$on('$locationChangeSuccess',
             function(evt, absNewUrl, absOldUrl) {
               //console.log('Success : old', absOldUrl, 'new ', absNewUrl);
        });
});;

app.controller("HTTPErrorController", function ($location) {
  console.log("HTTPErrorController")
});
Was it helpful?

Solution

There are two components acting separately asynchronously:

  • rendering of the template based on the route
  • XHR request responding with the authorization status.

By the time the http response is intercepted (btw response interception is deprecated), the route completes its part by rendering content and bootstrapping the corresponding angular controller (PrivateProfileController). On receiving the response, the response gets intercepted and the routing is done to /404. There comes the latency of 1 sec. (The time it took to complete the call to Grails at server side plus interception)

What can be done is making the authorization call part of routeProvider's resolve for that particular route:

$routeProvider
    .when('/:username/private', {
       templateUrl: '/js/angular/app/userprofile/templates/private.html',
       controller: 'PrivateProfileController',
       resolve: {
           authz: function($q){
               //Create a promise
               //Call the service (REST call to Grails)
               //Get back 404
               //Reject the promise if 404
               //route to 404
               //return promise
           }
       }
    })
    .when('/404', {
       templateUrl: '/js/angular/app/error/404.html' , 
       controller: 'HTTPErrorController'
    })
    .otherwise({

    });

If routing to /404 is a problem inside resolve then, use $routeChangeError event which gets fired on rejected promise.

Refer this question answered by Misko himself and this post as well to see how resolve works.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top