简体   繁体   中英

pass dynamic controller to angular directive

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?

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="angular.js@1.5.8" 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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM