4

I'm attempting to dynamically render directives based on a configuration array of directive names. Is this possible in angular? I also want these rendered directives to live within a single parent dom element rather than each getting a new wrapper (as you would with ng-repeat)

http://jsfiddle.net/7Waxv/

var myApp = angular.module('myApp', []);

myApp.directive('one', function() {
    return {
        restrict: 'A',
        template: '<div>Directive one</div>'
    }
});

myApp.directive('two', function() {
    return {
        restrict: 'A',
        template: '<div>Directive two</div>'
    }
});

function MyCtrl($scope) {
    $scope.directives = ['one', 'two'];
}

<div ng-controller="MyCtrl">
    <div ng-repeat="directive in directives">
        <div {{directive}}></div>
    </div>
</div>

EDIT: Since posting this, I've also tried:

.directive('parentDirective', function () {
  return {
    restrict: 'A',
    replace: true,
    link: function (scope, element) {
      scope.directives = ['one', 'two'];
      for (var i = 0; i < scope.directives.length; i++) { 
        element.prepend('<div ' + scope.directives[i] + '></div>')
      }
    }
  };
});

<div parent-directive></div>

With this, the templates from the prepended directives are not rendered.

2 Answers 2

5

Here what I came up with (took a long time)... The solution is pretty versatile though, you can modify $scope.directives array at will and the directives will be fabricated dynamically. You can also point to any particular property in the current scope to retrieve the directive list from.

Demo link

app.js

var myApp = angular.module('myApp', []);

myApp.directive('one', function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<div>Directive one</div>'
    }
});

myApp.directive('two', function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<div>Directive two</div>'
    }
});

myApp.directive('dynamic', function ($compile, $parse) {
  return {
    restrict: 'A',
    replace: true,
    link: function (scope, element, attr) {
      attr.$observe('dynamic', function(val) {
        element.html('');
        var directives = $parse(val)(scope);
        angular.forEach(directives, function(directive) {
          element.append($compile(directive)(scope));
        });
      });
    }
  };
});

function MyCtrl($scope) {
    $scope.directives = ['<one/>', '<two/>'];
    $scope.add = function(directive) {
        $scope.directives.push(directive);
    }
}

index.html

<div ng-controller="MyCtrl">
    <div dynamic="{{directives}}"></div>
    <button ng-click="add('<one/>')">Add One</button>
    <button ng-click="add('<two/>')">Add One</button>
</div>
Sign up to request clarification or add additional context in comments.

1 Comment

Rather than use element.append, did you think about setting restrict: 'C' and updating the class on the element? This way the directive can be added to existing dom elements or when creating a new one.
0

So the second attempt would have worked had I used $compile on the prepended directives like so:

.directive('parentDirective', function($compile)
    ....
element.prepend($compile('<div ' + scope.directives[i] + '"></div>')(scope));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.