要在模板中动态设置控制器,有对与控制器关联的构造函数 函数的引用会很有帮助。控制器的构造函数是传递给 Angular 的 module API 的 controller() 方法的函数。
这样做会有所帮助,因为如果传递给ngController 指令的字符串不是注册控制器的名称,那么ngController 会将字符串视为要在当前范围内评估的表达式。此范围表达式需要评估为控制器构造函数。
例如,假设 Angular 在模板中遇到以下情况:
ng-controller="myController"
如果没有注册名为 myController 的控制器,那么 Angular 将在当前包含的控制器中查看 $scope.myController。如果作用域中存在这个key,并且对应的值是一个控制器构造函数,那么就会使用这个控制器。
ngController 文档在其对参数值的描述中提到了这一点:“全局可访问构造函数的名称或在当前范围内计算为构造函数的表达式的名称。” Angular 源代码中的代码 cmets 更详细地说明了这一点 here in src/ng/controller.js。
默认情况下,Angular 无法轻松访问与控制器关联的构造函数。这是因为当您使用 Angular 的 module API 的 controller() 方法注册控制器时,它会将您传递给私有变量的构造函数隐藏起来。您可以在$ControllerProvider source code 中看到这一点。 (这段代码中的controllers变量是$ControllerProvider的私有变量。)
我对这个问题的解决方案是创建一个名为registerController 的通用帮助服务来注册控制器。此服务在注册控制器时同时公开控制器 和 控制器构造函数。这允许控制器以正常方式和动态方式使用。
这是我为执行此操作的 registerController 服务编写的代码:
var appServices = angular.module('app.services', []);
// Define a registerController service that creates a new controller
// in the usual way. In addition, the service registers the
// controller's constructor as a service. This allows the controller
// to be set dynamically within a template.
appServices.config(['$controllerProvider', '$injector', '$provide',
function ($controllerProvider, $injector, $provide) {
$provide.factory('registerController',
function registerControllerFactory() {
// Params:
// constructor: controller constructor function, optionally
// in the annotated array form.
return function registerController(name, constructor) {
// Register the controller constructor as a service.
$provide.factory(name + 'Factory', function () {
return constructor;
});
// Register the controller itself.
$controllerProvider.register(name, constructor);
};
});
}]);
以下是使用服务注册控制器的示例:
appServices.run(['registerController',
function (registerController) {
registerController('testCtrl', ['$scope',
function testCtrl($scope) {
$scope.foo = 'bar';
}]);
}]);
上面的代码将控制器注册为testCtrl,它还将控制器的构造函数公开为一个名为testCtrlFactory的服务。
现在您可以以通常的方式在模板中使用控制器--
ng-controller="testCtrl"
或动态--
ng-controller="templateController"
要使后者工作,您必须在当前范围内具有以下内容:
$scope.templateController = testCtrlFactory