通过 ng-controller 动态绑定控制器

Bind controllers dynamicaly via ng-controller

我希望使用带有一系列选项卡设置的 bootstrap.ui 选项卡集。这些选项卡设置包括用于处理其内容的控制器的名称。这样我的 'tab-control' 模板就会保持轻便和干净。

<div tabset>
    <div ng-repeat="tab in tabs"
         tab
         active="tab.isActive">
        <span tab-heading>{{ tab.title }}</span>
        <span ng-inlcude="tab.templateUrl" ng-controller="tab.controller"></span>
    </div>
</div>

(注意:我还没有在我的代码中使用 ng-include 属性,它首先测试了 ng-controller。)

首先我尝试给我们控制器名称...但是 ng-controller 不喜欢那样并且拒绝按预期运行。

然后我尝试通过下一个片段将名称翻译成控制器。

for (var tabIdx = 0; tabIdx < tabs.length; tabIdx++) {
    var tab = tabs[tabIdx];

    if (typeof tab.controllerName == 'string') {
        var childScope = tab.scope = tab.scope || $scope.$new();

        childScope.someValue = 'I am created as [' + tab.controllerName + '] requested.';

        tab.controller = $controller(tab.controllerName, { $scope: childScope });
    }
}

但是 angular 好心地告诉我 function 是预期的,但它得到了 controller (你会认为 ng-controller 不介意得到一个控制器) .

所以我将 $controller 调用更改为:

tab.controller = $controller(tab.contollerName, { $scope: childScope }).constructor;

虽然这确实有效,但有点...我的范围不是我想要的范围。

在此之后,我想到了为 ng-contoller 提供另一个功能:

tab.controller = $controller.bind(null, tab.contollerName, { $scope: childScope });

但是 ng-controller 找不到 $injectables。

有没有办法让它工作?

您可以简单地指定要在模板中使用的控制器:

控制器:

app.controller('rootCtrl', function($scope) {
  $scope.tabs = [
    { id: 1, name: 'tab1', template: 'template1.html' },
    { id: 2, name: 'tab2', template: 'template2.html' }
  ]
});

HTML:

<div ng-repeat="tab in tabs track by tab.id">
    <label class="tab">{{tab.name}}</label>
    <div ng-include="tab.template"></div>
 </div>

并在模板中:

<div ng-controller="ctrl1">
  ...
</div>

在此处查看示例 plunker:http://plnkr.co/edit/vkmBhP8cr8DpiHwbs2Rd?p=preview

我会为此创建一个指令,以动态分配控制器。

app.directive('tabCtrl', function ($controller) {
  return {
    restrict: 'A',
    controller: function ($scope, $element, $attrs) {
      return $controller($scope.tab.controller, {
        $scope:   $scope,
        $element: $element,
        $attrs:   $attrs
      });
    }
  };
}); 

<span ng-inlcude="tab.templateUrl" tab-controller="tab.controller"></span>

jsbin


如果你愿意,你可以更进一步,按照以下思路做一些事情:

app.directive('tab', function ($controller) {
  return {
    restrict: 'E',
    template: '<ng-include src="tab.template"></ng-include>',
    controller: function ($scope, $element, $attrs) {
      return $controller($scope.tab.controller, {
        $scope:   $scope,
        $element: $element,
        $attrs:   $attrs
      });
    }
  };
}); 

jsBin for the extended version