Reputation: 269
I’m building a directive, I’m calling ‘requires-authorization’ to wrap an ng-if directive. I’d like to use it as follows:
<requires-authorization role='SuperUser'>
<!— super secret user stuff goes here, within
the scope of this view's controller —>
</requires-authorization>
I’ve gotten as far as:
angular.module('myApp').directive('requiresAuthorization', function() {
return {
template: '<div ng-if=\'iAmInRole\' ng-transclude></div>',
restrict: 'E',
transclude: true,
scope: {
role: '@'
},
controller: function($scope, UserService) {
$scope.iAmInRole = (UsersService.myRoles.indexOf($scope.role) !== -1);
}
};
});
This works, but the content contained within the directive loses its scope, specifically the scope of the controller of the view it's found within. What am I overlooking?
jsfiddle for reference: http://jsfiddle.net/HbAmG/8/ Notice how the auth value isn't displayed inside the directive, but is available outside directive.
Upvotes: 3
Views: 1817
Reputation: 26838
You use ng-if
. It does transclusion as well, unfortunately using a child scope of it's own scope, which in turn is the isolate scope.
Below are the screenshots from Batarang. The first is your code with ng-if. 4 is the isolate scope, 6 the transcluded content.
The same without ng-if. The transcluded content is now 5 and a sibling of the isolate scope and, more importantly, child of the controller's scope.
Upvotes: 2
Reputation: 8789
Both ng-if
and ng-transclude
directives perform transclusion in your directive. In this case build-in transclude mechanism does not work fine and you should implement ngIf
of yourself to make it work as expected:
JavaScript
app.directive('requiresAuthorization', function () {
return {
template: '<div ng-transclude></div>',
restrict: 'E',
transclude: true,
scope: {
role: '@'
},
controller: function ($scope) {
$scope.iAmInRole = true;
},
link: function(scope, element, attr, ctrl, transcludeFn) {
transcludeFn(function(clone) { // <= override default transclude
element.empty();
if(scope.iAmInRole) { // <= implement ngIf by yourself
element.append(clone);
}
});
}
};
});
Plunker: http://plnkr.co/edit/lNIPoJg786O0gVOoro4z?p=preview
If ng-show
is an option for you to use instead of ng-if
it may be a very simple workaround as well. The only side effect is that hidden data will be presented in the DOM and hidden using CSS .ng-hide {display: none !important;}
.
JSFiddle: http://jsfiddle.net/WfgXH/3/
This post may also be useful for you since it describes the similar issue: https://stackoverflow.com/a/22886515/1580941
Upvotes: 4
Reputation: 33181
Once you define the scope
property in your directive, it becomes an isolated scope. With no access to the outside (well, in a way, the only way is ugly and should be avoided), except to the stuff you pass into it via the scope
property.
You'll need to either pass them into the directive: updated your jsfiddle
<requires-authorization role='Admin' data-auth-value='authValue' data-unauth-value='unAuthValue'>
<div>Inside directive. For Admin eyes only</div>
<p>{{authValue}}</p>
</requires-authorization>
// your directive scope
scope: {
role: '@',
authValue: '=',
unauthValue: '='
}
Or create a service/factory to act as a middle man to communicate.
Upvotes: 2