2

i am familiar with the syntax of controller & name but i'm trying to create a generic directive that will get a list of items and for each item i need to specify a controller.

This is my main directive:

function controlPanel() {
    var directive = {
        restrict: 'E',
        replace: true,
        scope: {
            controlPanelItems: "=sbControlPanelItems"  
        },
        templateUrl: 'control-panel.html',
        link: link
    };
    return directive;

    function link(scope, element) {
    }

}

Here is the directive template:

<sb-control-panel-item ng-repeat="controlPanelItem in controlPanelItems"
                                         sb-title="controlPanelItem.title"
                                         sb-template-url="controlPanelItem.templateUrl"
                                         sb-control-panel-item-controller="controlPanelItem.controller"></sb-control-panel-item>

My issue is with the sb-control-panel-item-controller attribute.

Angular throws exception when i'm passing variable, it work's great when i'm passing simple string (the name of the controller).

Here is the code of the control-panel-item directive:

function controlPanelItem() {
    var directive = {
        restrict: 'E',
        replace: true,
        scope: {
            title: '=sbTitle',
            templateUrl: '=sbTemplateUrl'
        },
        templateUrl: 'control_panel_item.html',
        controller: '@',
        name: 'sbControlPanelItemController',
        link: link
    };
    return directive;

    function link(scope, iElement, iAttributes, controller) {

    }

}

Maybe there is a way to inject the controller through the link function and then i'll just pass it through the scope?

1

1 Answer 1

4

You can use the $controller service to instantiate whatever controller dynamically inside the directive, check this plunkr. Just bear in mind that if you wanted to specify a controller statically now, you would need to enclose it in single quotes.

Basically the code would be like:

function MainCtrl() {
  this.firstCtrl = 'FirstCtrl';
  this.secondCtrl = 'SecondCtrl';
}


function FirstCtrl() {
  this.name = 'First Controller';
}

function SecondCtrl() {
  this.name = 'Second Controller';
}


function fooDirective() {
  return {
    scope: {
      ctrl: '='
    },
    template: '<div>{{foo.name}}</div>',
    controller: ['$controller', '$scope', function($controller, $scope) {
      var foo = $controller($scope.ctrl, {$scope: $scope});
      return foo;
    }],
    controllerAs: 'foo',
    link: function ($scope, $element, $attrs, $ctrl) {
      console.log($scope.ctrl);
    }
  };
}

angular
  .module('app', [])
  .directive('fooDirective', fooDirective)
  .controller('MainCtrl', MainCtrl)
  .controller('FirstCtrl', FirstCtrl)
  .controller('SecondCtrl', SecondCtrl);

and this would be the HTML

<!DOCTYPE html>
<html>

  <head>
    <script data-require="[email protected]" data-semver="1.5.8" src="https://code.angularjs.org/1.5.8/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-app="app" ng-controller="MainCtrl as main">
    <h1>
      Test
    </h1>

    <foo-directive ctrl="main.firstCtrl">
      "name: " {{foo.name}}
    </foo-directive>


    <foo-directive ctrl="main.secondCtrl">
      {{foo.name}}
    </foo-directive>
  </body>

</html>

======================================================================== WRONG OLD ANSWER

From this blog entry seems to be an undocumented property that allows you to do exactly what you need.

function FirstCtrl() {
  this.name = 'First Controller';
}

function SecondCtrl() {
  this.name = 'Second Controller';
}

function fooDirective() {
  return {
    scope: {},
    name: 'ctrl',
    controller: '@',
    controllerAs: 'foo',
    template: '<div></div>',
    link: function ($scope, $element, $attrs, $ctrl) {

    }
  };
}

angular
  .module('app', [])
  .directive('fooDirective', fooDirective)
  .controller('FirstCtrl', FirstCtrl)
  .controller('SecondCtrl', SecondCtrl);

So all you need to do in your directive is add a property name linked to the attribute you will use with the name of your controller.

<foo-directive ctrl="FirstCtrl"></foo-directive>
<foo-directive ctrl="SecondCtrl"></foo-directive>

If your directive, as per your question, needs to be from a property rather than a string, use {{}} notation:

<sb-control-panel-item ng-repeat="controlPanelItem in controlPanelItems"
                                         sb-title="controlPanelItem.title"
                                         sb-template-url="controlPanelItem.templateUrl"
                                         sb-control-panel-item-controller="{{controlPanelItem.controller}}"></sb-control-panel-item>
Sign up to request clarification or add additional context in comments.

4 Comments

You may want to read my question again, as i mentioned i am familiar with the name property, the problem is when i'm trying to pass a variable and not a string.
Use {{}} notation in the attribute, sorry I misread your question.
Can you add a working jsfiddle? Try to do it and still get an exception
Sorry, it wouldn't work like that, I have changed the answer with a plunkr attached.

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.