I've created a directive that accepts a callback as an attribute, e.g:
<my-directive callback-expression="someFunction()"> </my-directive>
The directive is reusable and hence I've given it an isolate scope. I want to show a button within the directive based on whether that callback-expression attribute is set.
App.directive('myDirective', function(){
restrict: 'E',
scope: {
callbackExpression: '&'
},
template: '<button ng-show="!!callbackExpression">Fire callback</button>'
});
The problem is, it's a function even if the expression is empty:
console.log($scope.callbackExpression) with a blank attribute results in:
function (locals) {
return parentGet(parentScope, locals);
}
My current solution is to have this line at the top of my link function:
if (attributes.callbackExpression) scope.callbackButton = true
Then ng-show on callbackButton
Are there any alternatives not requiring that extra line & scope property?
If you want to avoid putting anything on the stack then you can use the link function where you can access the attributes via attrs. Here are two approaches to that:
Link function option 1:
Instead of using template, you'd use this link function in your directive which conditionally adds your template:
link: function (scope, element, attrs) {
if (attrs.callbackExpression) {
var html = '<button>Fire callback</button>';
element.replaceWith(html);
}
}
Option 1 demo: http://jsfiddle.net/ZC4MZ/2/
Link function option 2 (better for large templates):
For large templates you can use $templateCache. First you add the template:
myApp.run(function($templateCache) {
$templateCache.put('myDirective.html', '<button>Fire callback</button>');
});
Then use it conditionally just like option 1 but with a $templateCache.get():
link: function (scope, element, attrs) {
if (attrs.callbackExpression) {
var html = $templateCache.get('myDirective.html');
element.replaceWith(html);
}
}
Making sure to inject $templateCache into your directive:
myApp.directive('myDirective', function ($templateCache) {
Here's a demo using $templateCache: http://jsfiddle.net/ZC4MZ/3/
Option using just the template:
To use the template you'll need a variable on the scope. For this you can keep everything as you have it, just add:
link: function(scope, element, attrs) {
scope.callbackExpression = attrs.callbackExpression;}
}
Template/scope variable demo: http://jsfiddle.net/ZC4MZ/5/
You can use the $attrs object that you can inject into in your directives to get to this information.
Markup:
<body ng-app="myApp" ng-controller="MyController">
<my-directive text="No Expression"></my-Directive>
<my-directive text="Expression" callback-expression="myCallback()"></my-Directive>
</body>
JS:
app.directive('myDirective', function(){
return {
restrict: "E",
scope: {
text: '@',
callbackExpression:'&'
},
templateUrl: "partial.html",
link: function($scope, $elem, $attrs) {
$scope.expressionCalled = false;
if ($attrs.callbackExpression) {
$scope.expressionCalled = true;
}
}
}
});
I created a working plunk for this example: http://plnkr.co/edit/K6HiT2?p=preview
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With