Question

TL;DR: Is there a way to dynamically set a directive based on a parameter value? Something similar to ng-class for setting css elements, but a way to set the directive based on the value in the scope. I would have the value in the scope so I could call:

<div class="data.directiveType"></div>

When

data.directiveType = "my-directive"

the div would become

<div class="my-directive"></div>

and myDirective would be invoked?

Detailed Question:

What I am trying to do is allow the user to add elements to the web application and I wanted the directive for each element to be added based on what the user clicks.

I have the following Directives:

app.directive("mySuperman", function(){
    //directive logic
});

app.directive("myBatman", function(){
    //directive logic
});

app.directive("myWonderWoman", function(){
    //directive logic
});

I have the following controller

app.controller("ParentCtrl", function($scope){
    $scope.superHeros = [];

    var superman = {directiveType: "my-superman"};
    var batman = {directiveType: "my-batman"};
    var wonderWoman = {directiveType: "my-wonder-woman"}

    $scope.addBatman = function()
    {
        var batmanInstance = {}
        angular.copy(batman, batmanInstance);
        $scope.superHeros.push(batmanInstance);
    }

    $scope.addSuperman = function()
    {
        var supermanInstance = {}
        angular.copy(superman, supermanInstance);
        $scope.superHeros.push(supermanInstance);
    }

    $scope.addWonderWoman = function()
    {
        var wonderwomanInstance = {}
        angular.copy(wonderWoman, wonderwomanInstance);
        $scope.superHeros.push(wonderwomanInstance);
    }

});

In the index.html I have

<body ng-controller="ParentCtrl>
    <a ng-click="addBatman()">Add Batman</a>
    <a ng-click="addSuperman()">Add Superman</a>
    <a ng-click="addWonderWoman()">Add WonderWoman</a>

    <div ng-repeat="hero in superHeros">
        <!-- The following doesn't work, but it is the functionality I am trying to achieve -->
        <div class={{hero.directiveType}}></div>
    <div>
</body>

The other way I thought of doing this was just using ng-include in the ng-repeat and adding the template url to the hero object instead of the directive type, but I was hoping there was a cleaner way that I could make better use of the data binding and not have to call ng-include just to call another directive.

Was it helpful?

Solution

You can create a directive that takes the directive to add as a parameter, adds it to the element and compiles it. Then use it like this:

<div ng-repeat="hero in superHeros">
  <div add-directive="hero.directiveType"></div>
</div>

Here is a basic example:

app.directive('addDirective', function($parse, $compile) {

  return {
    compile: function compile(tElement, tAttrs) {

      var directiveGetter = $parse(tAttrs.addDirective);

      return function postLink(scope, element) {

        element.removeAttr('add-directive');

        var directive = directiveGetter(scope);
        element.attr(directive, '');

        $compile(element)(scope);
      };
    }
  };
});

Demo: http://plnkr.co/edit/N4WMe8IEg3LVxYkdjgAu?p=preview

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top