I\'m trying to build a directive that takes care of adding more directives to the element it is declared on. For example, I want to build a directive that t
Here's a solution that moves the directives that need to be added dynamically, into the view and also adds some optional (basic) conditional-logic. This keeps the directive clean with no hard-coded logic.
The directive takes an array of objects, each object contains the name of the directive to be added and the value to pass to it (if any).
I was struggling to think of a use-case for a directive like this until I thought that it might be useful to add some conditional logic that only adds a directive based on some condition (though the answer below is still contrived). I added an optional if
property that should contain a bool value, expression or function (e.g. defined in your controller) that determines if the directive should be added or not.
I'm also using attrs.$attr.dynamicDirectives
to get the exact attribute declaration used to add the directive (e.g. data-dynamic-directive
, dynamic-directive
) without hard-coding string values to check for.
Plunker Demo
angular.module('plunker', ['ui.bootstrap'])
.controller('DatepickerDemoCtrl', ['$scope',
function($scope) {
$scope.dt = function() {
return new Date();
};
$scope.selects = [1, 2, 3, 4];
$scope.el = 2;
// For use with our dynamic-directive
$scope.selectIsRequired = true;
$scope.addTooltip = function() {
return true;
};
}
])
.directive('dynamicDirectives', ['$compile',
function($compile) {
var addDirectiveToElement = function(scope, element, dir) {
var propName;
if (dir.if) {
propName = Object.keys(dir)[1];
var addDirective = scope.$eval(dir.if);
if (addDirective) {
element.attr(propName, dir[propName]);
}
} else { // No condition, just add directive
propName = Object.keys(dir)[0];
element.attr(propName, dir[propName]);
}
};
var linker = function(scope, element, attrs) {
var directives = scope.$eval(attrs.dynamicDirectives);
if (!directives || !angular.isArray(directives)) {
return $compile(element)(scope);
}
// Add all directives in the array
angular.forEach(directives, function(dir){
addDirectiveToElement(scope, element, dir);
});
// Remove attribute used to add this directive
element.removeAttr(attrs.$attr.dynamicDirectives);
// Compile element to run other directives
$compile(element)(scope);
};
return {
priority: 1001, // Run before other directives e.g. ng-repeat
terminal: true, // Stop other directives running
link: linker
};
}
]);