Reputation: 3074
I'm trying to make a directive that conditionally adds a line break if an angular expression is non-blank. So far, I have this:
// this will show text with a <br> conditionally if the text is non-blank
angular.module('myApp.directives').directive('brIf', function () {
return {
scope: {
text: '='
},
template: '<span ng-show="text && text.trim().length">{{ text }}<br/></span>'
};
});
Which works if I use it like this (any part of the address might be undefined or blank):
<br-if text="address.number + ' ' + address.street + ' ' + address.apt"></br-if>
But what I really want is a directive I can use like this:
<!-- put a br at the end of all this jazz, only if the expression is not blank -->
<br-if>{{address.number}} {{address.street}} {{address.apt}}</br-if>
...to avoid all of the string math and the text= attribute. I know I can write a link function in my directive that gets at the html content via the element parameter (I think?), but I don't know how to use the contents of that element in the template. In other words, see my question inside the link function ...
// this will show text with a <br> conditionally if the text is non-blank
angular.module('myApp.directives').directive('brIf', function () {
return {
scope: {
text: '='
},
link: function(scope, elm, attrs, ctrl) {
// I want the text of elm here to be used instead of 'text'
// in my template below. Is this possible?
},
template: '<span ng-show="text && text.trim().length">{{ text }}<br/></span>'
};
});
Upvotes: 2
Views: 4294
Reputation: 4685
You don't need a full transclusionFn
for most cases. If you set transclude: true
in your directive options, you can just add ng-transclude
to your template where you want the content added:
<div class="example" style="background: blue; height: 30px; width: 30px" ng-transclude></div>
Reference: https://stackoverflow.com/a/16697788/175830
Upvotes: 2
Reputation: 38490
You can use transclusion:
app.directive('brIf', function($interpolate) {
return {
restrict: 'E',
template: '<span ng-show="text && text.trim().length">{{ text }}<br/></span>',
transclude: true,
link: function(scope, element, attrs, controller, transclusionFn) {
transclusionFn(scope, function(clone) {
scope.text = $interpolate(clone[0].innerHTML)(scope);
});
}
};
});
What you are after is clone
which will be a fresh compiled copy of your transcluded content. This means that for example clone[0].innerHTML
will be:
{{address.number}} {{address.street}} {{address.apt}}
You can then use the $interpolate
service to compile the string into an interpolation function, use this function to compute the interpolated string against a scope and use the result:
var interpolationFn = $interpolate(clone[0].innerHTML);
var interpolatedString = interpolationFn(scope);
scope.text = interpolatedString;
Or simply:
scope.text = $interpolate(clone[0].innerHTML)(scope);
Demo: http://plnkr.co/edit/VNauZ0Kkr1HLCnsWTgyO?p=preview
Upvotes: 5