9

我有一个这样定义的应用程序:

angular.module("myApp", [...])
  .config(function ($stateProvider, $controllerProvider) {
    if (isControllerDefined(controllerName)) {
      do_stuff();
    }
  })

控制器是这样定义的:

angular.module("myApp")
  .controller("myController", function ($scope) { ... });

如果我有控制器的名称,我如何定义isControllerDefined()(在上面的配置中)检查给定的控制器是否存在?我觉得我应该能够执行以下操作之一:

var ctrl = angular.module("myApp").getController("myController");
var ctrl = $controllerProvider.get("myController");

或类似的东西......但我找不到任何功能。帮助?

4

5 回答 5

9

可以检查控制器是否存在的服务示例。请注意,它会查找具有指定名称的全局函数以及$controller提供程序中的控制器。

angular.service('ControllerChecker', ['$controller', function($controller) {
  return {
    exists: function(controllerName) {
      if(typeof window[controllerName] == 'function') {
        return true;
      }
      try {
        $controller(controllerName);
        return true;
      } catch (error) {
        return !(error instanceof TypeError);
      }
    }
  };
}]);

请参阅小提琴的用法。

于 2014-09-26T10:43:51.067 回答
6

前几天我遇到了同样的问题。我对当前接受的答案有一些问题,即因为我的一个控制器在实例化时正在对服务器执行初始化调用以填充一些数据(即):

function ExampleController($scope, ExampleService) {
    ExampleService.getData().then(function(data) {
        $scope.foo = data.foo;
        $scope.bar = data.bar
    });
}

就目前而言,当前接受的答案实际上会在丢弃控制器之前实例化控制器。这导致对每个请求进行多个 API 调用(一个用于验证控制器是否存在,一个用于实际使用控制器)。

我在$controller 源代码中进行了一些挖掘 ,发现有一个未记录的参数可以传入调用later,这将延迟实例化。但是,它仍会运行所有检查以确保控制器存在,这是完美的!

angular.factory("util", [ "$controller", function($controller) {
    return {
        controllerExists: function(name) {
            try {
                // inject '$scope' as a dummy local variable
                // and flag the $controller with 'later' to delay instantiation
                $controller(name, { "$scope": {} }, true);
                return true;
            }
            catch(ex) {
                return false;
            }
        }
    };
}]);

更新:作为装饰者可能要容易得多:

angular.config(['$provide', function($provide) {
    $provide.delegate('$controller', [ '$delegate', function($delegate) {
        $delegate.exists = function(controllerName) {
            try {
                // inject '$scope' as a dummy local variable
                // and flag the $controller with 'later' to delay instantiation
                $delegate(controllerName, { '$scope': {} }, true);
                return true;
            }
            catch(ex) {
                return false;
            }
        };

        return $delegate;
    }]);
}]);

然后你可以简单地注入$controller和调用exists(...)

function($controller) {
    console.log($controller.exists('TestController') ? 'Exists' : 'Does not exist');
}
于 2015-09-14T01:50:30.703 回答
3

目前没有简单的方法来获取控制器列表。这是隐藏的,仅供内部使用。您必须转到源代码并添加一个返回内部控制器变量的公共方法(在 $ControllerProvider 函数中) https://github.com/angular/angular.js/blob/master/src/ng/controller。 js#L16

this.getControllers = function() {
    return controllers;
    // This will return an object of all the currently defined controllers
  };

然后你可以做

app.config(function($controllerProvider) {
    var myCtrl = $controllerProvider.getControllers()['myController'];
});
于 2013-11-01T23:07:02.897 回答
3

由于 angular 1.5.1 (在撰写本文时尚未发布),有一种新方法可以通过该方法检查控制器是否存在$ControllerProvider.has('MyCtrlName')

Github 问题:https ://github.com/angular/angular.js/issues/13951

Github PR:https ://github.com/angular/angular.js/pull/14109

直接在 1.5.1 中提交反向移植:https ://github.com/angular/angular.js/commit/bb9575dbd3428176216355df7b2933d2a72783cd


免责声明:由于很多人对这个功能感兴趣,所以我做了一个 PR,因为我也需要它是我的一些项目。玩得开心!:)

此 PR 是基于 @trekforever 的回答,感谢您的提示 :)

于 2016-02-23T22:46:26.437 回答
2

您可以使用 $controller 服务并执行 $controller('myController') 并在其周围包裹一个 try-catch,以便知道它是否失败。

于 2013-11-02T01:10:06.070 回答