根据用户的角色在单个视图中显示不同的内容

Ole*_*sov 29 angularjs angularjs-directive

让我们假设我的角度SPA应用程序中有一个菜单,现在我希望向所有用户显示基本选项,例如家庭,关于我们,运营商机会等.

我还想提供其他几个选项,例如管理用户,管理员帖子等,这些选项只会显示给管理员.

我们还假设我们有一个API访问点,它为我提供了用户角色,或者更好的是,用户角色位于从/ api/users/me检索的对象中.

将这些管理工具封装为普通用户查看的最佳方法是什么?

视图中是否存在某种继承?像在Django?中,有没有办法隐藏未经授权的用户的DOM元素?(是的,我知道它是客户端).

我真的不想对菜单使用不同的视图,因为它应该是一个通用的组件.

我想,如果我之前所有问题的答案都是否定的,那么剩下的问题是:对此最好的实施是什么?自定义指令("E"+"A")说:

<limitedAccss admin>Edit page</limitedAccess>
 <limitedAccss user>view page</limitedAccess>
Run Code Online (Sandbox Code Playgroud)

或者只是使用带有用户对象条件的常规ng-show?

Ole*_*sov 38

解决方案就是这个小提琴:

http://jsfiddle.net/BmQuY/3/

var app = angular.module('myApp', []);

app.service('authService', function(){

  var user = {};
  user.role = 'guest';
  return{
    getUser: function(){
      return user;
    },
    generateRoleData: function(){
      /* this is resolved before the 
         router loads the view and model.
         It needs to return a promise. */
      /* ... */
    }
  }
});

app.directive('restrict', function(authService){
    return{
        restrict: 'A',
        priority: 100000,
        scope: false,
        compile:  function(element, attr, linker){
            var accessDenied = true;
            var user = authService.getUser();

            var attributes = attr.access.split(" ");
            for(var i in attributes){
                if(user.role == attributes[i]){
                    accessDenied = false;
                }
            }


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


            return function linkFn() {
                /* Optional */
            }
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

如果你想在IE 7或8中使用这个指令,你需要手动删除元素的子节点,否则会抛出一个错误:

  angular.forEach(element.children(), function(elm){
    try{
      elm.remove();
    }
    catch(ignore){}
  });
Run Code Online (Sandbox Code Playgroud)

可能的用法示例:

<div data-restrict access='superuser admin moderator'><a href='#'>Administrative options</a></div>
Run Code Online (Sandbox Code Playgroud)

:使用噶+茉莉花单元测试 注意:done回调函数仅适用于茉莉花2.0,如果您使用的1.3,你应该使用waitsFor代替.

  describe('restrict-remove', function(){
    var scope, compile, html, elem, authService, timeout;
    html = '<span data-restrict data-access="admin recruiter scouter"></span>';
    beforeEach(function(){
      module('myApp.directives');
      module('myApp.services');
      inject(function($compile, $rootScope, $injector){
        authService = $injector.get('authService');
        authService.setRole('guest');
        scope = $rootScope.$new();
        // compile = $compile;
        timeout = $injector.get('$timeout');
        elem = $compile(html)(scope);
        elem.scope().$apply();
      });
    });
    it('should allow basic role-based content discretion', function(done){
        timeout(function(){
          expect(elem).toBeUndefined(); 
          done(); //might need a longer timeout;
        }, 0);
    });
  });
  describe('restrict-keep', function(){
    var scope, compile, html, elem, authService, timeout;
    html = '<span data-restrict data-access="admin recruiter">';
    beforeEach(function(){
      module('myApp.directives');
      module('myApp.services');
      inject(function($compile, $rootScope, $injector){
        authService = $injector.get('authService');
        timeout = $injector.get('$timeout');
        authService.setRole('admin');
        scope = $rootScope.$new();
        elem = $compile(html)(scope);
        elem.scope().$apply();
      });
    });

    it('should allow users with sufficient priviledsges to view role-restricted content', function(done){
      timeout(function(){
        expect(elem).toBeDefined();
        expect(elem.length).toEqual(1);
        done(); //might need a longer timeout;
      }, 0)
    })
  });
Run Code Online (Sandbox Code Playgroud)

元素的通用访问控制指令,不使用ng-if(仅从V1.2开始 - 当前不稳定),或者实际上不从DOM中删除元素的ng-show.