Advanced manipulating DOM in AngularJS directive

2019-08-05 13:31发布

问题:

I'm resolving rights in AngularJS application... I would like to use custom directive for resolving what user can see by his role. It's only client side design. If user entry on page what he hasn't access, server return 403 for all requests for data from this page. My actual solution looks like this:

<li ng-repeat="menuItem in navigationItems" class='{{menuItem.css}}' restrict-access="menuItem.restrict"> <a href="#/{{menuItem.url}}"> <div class="label"> <span class="icon"> <span class="title">{{menuItem.title}}</span> </span> </div> </a> </li>

.directive('restrictAccess', function() {
    return {
        restrict: 'EA',
        prioriry: 100000,
        scope: {
            restrictAccess: "=restrictAccess"
        },
        controller: ['$scope', '$element', function($scope, $element) {

            var accessDenied = true;
            var userRole = App.LoggedUser.userRole;

            var attributes = $scope.restrictAccess.split(" ");
            for (var i in attributes) {
                if (userRole == attributes[i]) {
                    accessDenied = false;
                }
            }

            if (accessDenied) {
                $element.remove();
            }

        }]
    };
})

There are many problems...

Controllers of widgets rendered by ng-include are faster than my directive and some ajax requests are sended to server before I remove widgets from DOM. I need directive what stops controllers in their child elements.

I hope it is understandable... Here is testing Fiddle

Thanks David

回答1:

I used angularjs authentication interceptor in my last project. It suits what you need..

Inteceptor stores the request on every service request and broadcast message.. You can get broadcasted messages on your controllers. Here is the code I dealt with.. Checkout auth interceptor.

/**
 * @license HTTP Auth Interceptor Module for AngularJS
 * (c) 2012 Witold Szczerba
 * License: MIT
 */
angular.module('http-auth-interceptor', [])

    .provider('authService', function() {
        /**
         * Holds all the requests which failed due to 401 response,
         * so they can be re-requested in future, once login is completed.
         */
        var buffer = [];

        /**
         * Required by HTTP interceptor.
         * Function is attached to provider to be invisible for regular users of this service.
         */
        this.pushToBuffer = function(config, deferred) {
            buffer.push({
                config: config,
                deferred: deferred
            });
        }

        this.$get = ['$rootScope','$injector', function($rootScope, $injector) {
            var $http; //initialized later because of circular dependency problem
            function retry(config, deferred) {
                $http = $http || $injector.get('$http');
                $http(config).then(function(response) {
                    deferred.resolve(response);
                });
            }
            function retryAll() {
                for (var i = 0; i < buffer.length; ++i) {
                    retry(buffer[i].config, buffer[i].deferred);
                }
                buffer = [];
            }

            return {
                loginConfirmed: function() {
                    $rootScope.$broadcast('event:auth-loginConfirmed');
                    $rootScope.$apply();
                    //retryAll();
                }
            }
        }]
    })

/**
 * $http interceptor.
 * On 401 response - it stores the request and broadcasts 'event:angular-auth-loginRequired'.
 */
    .config(function($httpProvider, authServiceProvider) {

        var interceptor = ['$rootScope', '$q',function($rootScope, $q,$cookies) {
            function success(response) {
                return response;
            }

            function error(response) {
                if (response.status === 401) {                  
                    var deferred = $q.defer();
                    authServiceProvider.pushToBuffer(response.config, deferred);
                    $rootScope.$broadcast('event:auth-loginRequired');
                    return deferred.promise;
                }
                else if (response.status === 404 || response.status === 400) {

                    $rootScope.$broadcast('event:not-found');
                }
                // otherwise
                return $q.reject(response);
            }

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

        }];
        $httpProvider.responseInterceptors.push(interceptor);
    });

And in your controller :

$rootScope.$on('event:auth-loginRequired', function() {
     //do what you want, for example throw a message        
});