Eduardo
Eduardo

Reputation: 7141

Angular Directive that takes a string

I am trying to create a directive that can show or hide the element it is on dependent on whether a user has a visibility of a feature:

See my Plunker example

I would like to apply this directive like below:

<div feature="some-feature-name">
   I have the power!
</div>

angular
.module('app', [])
.directive('feature', ['userService' function(){
    return {
        restrict:'A',
        scope: {},
        link: function(scope, elem, attrs, ngModel){
          // Logic to work out whether someone is permitted to see that feature

          if(userService.canSeeFeature(featureName){
          }
          // Hides the the element it is on if not.

        }
    };
}]);

Is this possible?

Upvotes: 1

Views: 62

Answers (2)

Rhumborl
Rhumborl

Reputation: 16609

There are two main steps to doing this - getting hold of the feature to check from the attribute and doing the show/hide of the element.

Getting the feature

The first thing to note is how to get hold of the feature from the attribute

<div feature="y">AccessGranted</div>

You do this in the using the attrs parameter already in the link method. Simply

link: function(scope, elem, attrs){
    var theFeature = attrs['feature'];
    var hasAccess = userService.canSeeFeature(theFeature);
}

Hiding the element

Next you need to hide the element if they do not have access. There are a couple of options for doing this.

The "pure Angular" way to do this is to set a variable on your scope saying whether the user has access or not, then use ng-show to only show it if the variable is true:

link: function(scope, elem, attrs){
    scope.hasAccess = userService.canSeeFeature(attrs['feature']);
}

<div feature="y" ng-show="hasAccess">Access Granted</div>

However the point of the directive is to do this for you. In this case, I think it is reasonable to use some simple jQuery (more specifically jqLite) to do this in the directive code. If you have full jQuery in your page elem.hide() is nicer, but jqLite doesn't support this, so you will need to use css():

link: function(scope, elem, attrs){
    // check for access
    if(!userService.canSeeFeature(attrs['feature'])) {
        // hide the element
        elem.css('display', 'none');
    }
}

Sample

Here is a working sample based on your plunkr:

angular
  .module('app', [])
  .service('userService', function() {
    return {
      canSeeFeature: function(feature) {
        // test - only allow access to y
        return feature === 'y';
      }
    }
  })
  .directive('feature', ['userService', function(userService) {
      return {
          restrict:'A',
          scope: {},
          link: function(scope, elem, attrs, ngModel){
            // check for access
            if(!userService.canSeeFeature(attrs['feature'])) {
              // access denied - hide the element
              elem.css('display', 'none');
            }
          }
      };
  }]);
<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <title>AngularJS Formatters and Parse</title>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js"></script>
</head>

<body ng-app="app">

  <div feature="y">y - I have the power!</div>
  <div feature="n">n - I don't have the power :(</div>
  <div feature="y">y - I also have the power!</div>

</body>

</html>

Upvotes: 1

Guillaume
Guillaume

Reputation: 13138

A modified version of ngShow directive :

var featureDirective = ['$animate', 'userService', function($animate, userService) { 
   return { 
     restrict: 'A', 
     multiElement: true, 
     link: function(scope, element, attr) { 
       scope.$watch(attr.feature, function featureWatchAction(value) {
         $animate[userService.isAllowed(value) ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, { 
           tempClasses: NG_HIDE_IN_PROGRESS_CLASS 
         }); 
       }); 
     } 
   }; 
 }]; 

Upvotes: 1

Related Questions