Reputation: 21892
I'm sure this has been asked before, but it's kind of hard to put into a question and, therefore, is also hard to search for...
A piece of my app uses one of several third-party directives. The directives I'm messing with, at the moment, are those in the xeditable lib, but this question isn't just about that lib, as I've come across this need before.
My code, currently, looks something like the following:
<div ng-switch on="editTypeNeeded">
<div ng-switch-when="textarea" editable-textarea="myVar" onbeforesave="doBeforeSaveStuff($data)" class="whatever" ng-class="whatever2()" ng-mouseover="doStuff()" some-other-directive="doMoreStuff()">
{{myvar}}
...
and other stuff
</div>
<div ng-switch-when="textfield" editable-text="myVar" onbeforesave="doBeforeSaveStuff($data)" class="whatever" ng-class="whatever2()" ng-mouseover="doStuff()" some-other-directive="doMoreStuff()">
{{myvar}}
...
and other stuff
</div>
<div ng-switch-when="checkbox" editable-checkbox="myVar" onbeforesave="doBeforeSaveStuff($data)" class="whatever" ng-class="whatever2()" ng-mouseover="doStuff()" some-other-directive="doMoreStuff()">
{{myvar}}
...
and other stuff
</div>
<div ng-switch-when="date" editable-bsdate="myVar" onbeforesave="doBeforeSaveStuff($data)" class="whatever" ng-class="whatever2()" ng-mouseover="doStuff()" some-other-directive="doMoreStuff()">
{{myvar}}
...
and other stuff
</div>
...
etc...
</div>
That's a TON of code duplication when the only thing that changes between each switch
option is "editable-textarea", "editable-text", etc.
What I would like is to replace all of the above with something like this:
<div {{directiveName}}="myVar" onbeforesave="doBeforeSaveStuff($data)" class="whatever" ng-class="whatever2()" ng-mouseover="doStuff()" some-other-directive="doMoreStuff()">
{{myvar}}
...
and other stuff
</div>
which, obviously, doesn't work, but there's got to be a way to do something like that...
Update:
I ended up using the selected answer, but with a slight modification to allow for both a variable directive name AND a directive value. Like so:
.directive('useDirective', function ($compile) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
attrs.$observe('useDirective', function(directiveNameAndValue) {
if (directiveNameAndValue) {
var nameAndValue = directiveNameAndValue.split('='),
dirName = nameAndValue[0],
value = nameAndValue[1] || '';
elem.attr(dirName, value);
elem.removeAttr('use-directive');
$compile(elem)(scope);
}
});
}
};
});
And I use it like this:
<div use-directive="{{getDirectiveType(value)}}=value" class="pointer" onbeforesave="notifyOfChange($data)">{{value}}</div>
Plunker example: http://plnkr.co/edit/JK5TkFKA2HutGJOrMo8a?p=preview
Update 2:
I've found that the above technique doesn't seem to play nicely with the angular-animate.js lib. It causes that lib to kick up the following error a bunch of times:
TypeError: Cannot read property 'parentNode' of undefined
at angular-animate.js:1203
at angular-animate.js:539
at n.$digest (angular.js:14358)
at n.$apply (angular.js:14571)
at angular.js:16308
at e (angular.js:4924)
at angular.js:5312
though, the page still seems to work fine.
Upvotes: 2
Views: 1044
Reputation: 19193
You can create a directive to-rule-them-all:
<div lord-of-the-directives="{{directiveName}}">
Which would be like
module.directive('lordOfTheDirectives', function ($compile) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
attrs.$observe('lordOfTheDirectives', function(dirName) {
if (dirName) {
elem.append('<div ' + dirName + '>');
$compile(elem)(scope);
}
});
}
};
});
(not tested but that's the idea)
Update by request in comment, to keep the element as is (with its classes and stuff):
module.directive('lordOfTheDirectives', function ($compile) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
attrs.$observe('lordOfTheDirectives', function (dirName) {
if (dirName) {
elem.attr(dirName, '');
elem.removeAttr('lord-of-the-directives');
$compile(elem)(scope);
}
});
}
};
});
Upvotes: 4