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