ThinkingInBits
ThinkingInBits

Reputation: 11462

Rendering AngularJS directives from array of directive names in a parent directive or controller

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.

Upvotes: 4

Views: 1630

Answers (2)

Buu
Buu

Reputation: 50365

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>

Upvotes: 5

ThinkingInBits
ThinkingInBits

Reputation: 11462

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));

Upvotes: 0

Related Questions