Reputation: 1874
I'd like to use an AngularJS directive to disable specific parts of forms throughout the application based on whether the user has a specific role (given as attribute value; may be different per element). The directive's code goes like this:
/** @ngInject */
function PermissionDirective() {
var directive = {
restrict: 'A',
scope: true,
bindToController: true,
controller: controller,
controllerAs: 'permission',
link: link
};
function link(scope, element, attrs) {
scope.soPermission = attrs.soPermission;
}
return directive;
}
/** @ngInject */
function controller($scope, $attrs, ...) {
var permission = this;
permission.granted = false;
$scope.soPermission = $attrs.soPermission;
init();
function init() {
var requiredPermission = $scope.soPermission;
permission.granted = // determine if user can use element
}
}
Note that it needs its own scope to work. The usage in HTML is:
<button type="button" ng-disabled="... || !permission.granted" so-permission="WRITE">
All's fine as long as so-permission
is the only directive in the element with a new scope. However, some elements also use a confirm modal which also seems to require a new/isolated scope. This results in a Multiple directives... Angular error.
My question is: how do you work around this? How do I rework the so-permission
directive to get rid of the internal scope and still keep it working (since I can't touch the confirm
thing as it's a library)?
Upvotes: 1
Views: 166
Reputation: 74
What are the different permissions you intend to give to the form elements? Maybe stepping back and looking at it from a simpler, HTML perspective is possible?
Instead of creating a directive, could you simply assign the readonly attribute using ng-attr-readonly with a function to determine if it should be present or not. That function could exist in your form's controller.
<input type="text" ng-attr-readonly="getPermissions()" />
And the function:
this.getPermissions = function() {
if (this.granted === 'READ') return undefined;
return 'readonly';
}
Would this approach work for you situation?
UPDATE: Make this function into a Factory and re-use it.
angular.module("myApp").factory("PermissionsFactory",PermissionsFactory);
function PermissionsFactory() {
factory = {
getPermissions: getPermissions
}
return factory;
function getPermissions(ctrl) {
if (ctrl.granted === 'READ') return undefined;
return 'readonly';
}
}
Then, in your controller (assuming you have injected it):
this.getPermissions = PermissionsFactory.getPermissions
Finally, in your HTML, be sure to pass the controller into the function, since the function is no longer part of the controller and will need the scope of the controller to check the permissions:
<input type="text" ng-attr-readonly="getPermissions(permission)" />
Upvotes: 1
Reputation: 1577
you should use $parse service, to communicate with scope: /
** @ngInject */
function PermissionDirective() {
var directive = {
restrict: 'A',
link: link
};
function link(scope, element, attrs) {
var getter = $parse(attrs.soPermission);
var setter = getter.setter;
setter(scope, val); // set value to scope
var value = getter(scope); //get value from scope
}
return directive;
}
also you could use scope.$watch, to sync values in dynamic.
Upvotes: 0
Reputation: 562
In angular js, we can have at the most one isolated directive on a single element. I would suggest try to decorate your directive. Check this article for more details Decorating Directives
Upvotes: 0