Madushan
Madushan

Reputation: 7458

Angular - Loading a view without changing the url

I'm working on a project which has several views, which some of the views may not be accessible to a given user. What I want to do is that, if a user navigates to a url that is restricted (due to his permissions), lets say '/project/manhatten/security' I want to display a view (an html partial) which simply says 'Access Denied'.

But I want to display the view without changing the url. I want the url to stay '/project/manhatten/security', so the user can copy the url and give it to someone with enough permission, and it would work fine.

What is the best way to achieve this ? Can I still use ng-view or a combination of ng-view and ng-include ?

Thanks in Advance.

Upvotes: 0

Views: 1120

Answers (1)

bekite
bekite

Reputation: 3444

I don't know of a way on how to restrict access to a specific view in angular. I think you shouldn't restrict views. What you should do is restrict access to your api. So if a user doesn't have the privilege to delete a project. Simply send a 401 from the server when he calls the api. On the client side handle this 401 in angular with an $http interceptor.

I would do the following:

In your index.html create an element/directive to display the error message

index.html

  <div ng-controller=ErrorMessageCtrl ng-show=error.message>
    {{error.message}}

  <ng-view></ng-view>

The ErrorMessageCtrl will get notified when an access denied error occured:

.controller('ErrorMessageCtrl', function ($scope) {
  $scope.error = {}
  $scope.$on('error:accessDenied', function(event, message) {
    $scope.error.message = message
  })
})

Create an interceptor service to handle http 401 auth error:

.factory('authErrorInterceptor', function ($q, $rootScope) {
  return {
    response: function (response) {
      return response
    },
    responseError: function(rejection) {
      if (rejection.status === 401) {
        $rootScope.$broadcast('error:accessDenied', 'Access Denied')
      }
      return $q.reject(rejection)
    }
  }
})

add the interceptor service to $httpProvider

.config(function ($httpProvider, $routeProvider) {
  $httpProvider.interceptors.push('authErrorInterceptor')
  $routeProvider.when('/project/manhatten/security', {
    template: '<div><h1>Secure Page</h1>secure data from server: {{data}}</div>',
    controller: 'SecureDataCtrl'
  })
})

$http.get('/api/some/secure/data') returns a 401 http status code

.controller('SecureDataCtrl', function ($scope, $http) {
  $scope.data = 'none'
  $http.get('/project/manhatten/security')
    .success(function (data) {
      $scope.data = 'secure data'
    })
})

Please keep in mind that this was hacked in 10 minutes. You need to do some refactoring. Like creating an errorMessage directive which gets the error notification service injected and not broadcasting the error message to the scope.

Upvotes: 3

Related Questions