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)?
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)" />