42

在 Angular 1.2 中,ngRoute它是一个单独的模块,因此您可以使用其他社区路由器ui.router代替。

我正在编写一个开源模块,旨在为多个不同的路由器实现工作。那么如何检查哪个路由器已加载或存在?

我在模块中的工厂内执行以下操作,但它并没有按照我期望的方式工作:

if (angular.module("ngRoute"))
  // Do ngRoute-specific stuff.
else if (angular.module("ui.router"))
  // Do ui.router-specific stuff.

对于未加载的任何模块,它都会引发错误。例如,如果应用程序正在使用ui.router,则ngRoute检查时会引发以下错误:

未捕获的错误:[$injector:nomod] 模块“ngRoute”不可用!您要么拼错了模块名称,要么忘记加载它。如果注册模块,请确保将依赖项指定为第二个参数。

4

7 回答 7

57

我不知道在不引发错误的情况下进行检查的方法;但是,请注意问题在于它是一个Uncaught Error,而不是引发了错误。捕获此类错误的模式如下。

try { angular.module("ngRoute") } catch(err) { /* failed to require */ }

如果发现错误,您可以尝试其他模块,如果没有,您可以使用第一个。

如果每个模块的行为都相同,则可以执行以下操作,其中我们定义一个函数,它将尝试列出的模块名称中的第一个,如果抛出错误,请尝试下一个选项。

var tryModules = function(names) {
  // accepts a list of module names and
  // attempts to load them, in order.

  // if no options remain, throw an error.
  if( names.length == 0 ) {
    throw new Error("None of the modules could be loaded.");
  }

  // attempt to load the module into m
  var m;
  try {
    m = angular.module(names[0])
  } catch(err) {
    m = null;
  }

  // if it could not be loaded, try the rest of
  // the options. if it was, return it.
  if( m == null ) return tryModules(names.slice(1));
  else return m;
};

tryModules(["ngRoute", "ui.router"]);
于 2013-10-06T08:11:39.473 回答
9

我会测试服务而不是模块本身。

// In controller
if($injector.has('$route')){

}
if($injector.has('$state')){

}

// In angular config
if($injector.has('$routeProvider')){

}
if($injector.has('$stateProvider')){

}
于 2015-10-20T20:22:10.310 回答
6

原来的答案是合法的。但是,作为替代方案,我在需要“查找或创建”模块时写了这个。有许多用例,但通常,它让您不必担心文件加载顺序。您可以将其放在initialModules.js... 中,也可以在所有单个服务/指令文件的顶部以此类开头。这个小功能对我来说就像一个魅力:

var initialModules = [
  {name: 'app.directives', deps: ['ui.mask']},
  {name: 'app.services'},
  {name: 'app.templates'},
  {name: 'app.controllers'}
];

initialModules.forEach(function(moduleDefinition) {
  findOrCreateModule(moduleDefinition.name, moduleDefinition.deps);
});

function findOrCreateModule(moduleName, deps) {
  deps = deps || [];
  try {
    angular.module(moduleName);
  } catch (error) {
    angular.module(moduleName, deps);
  }
}


///// OR... in like "myDirective.js"
findOrCreateModule('app.directives').directive('myDirective', myDirectiveFunction);
于 2015-08-11T23:25:33.637 回答
1

如果您装饰angular.module以将名称存储在数组中,那么您只需检查数组是否包含您的模块名称。

装饰 angular.module

请参阅@dsfq 对 SO 的回答

这需要在加载 angular 之后但在开始加载任何 angular 模块之前发生。

检查您的模块

if(angular.modules.indexOf("ngRoute") > -1) ...

于 2016-07-01T09:29:48.720 回答
0

AngularJS 1.6.3 及更高版本可以检查模块是否通过 $injector 服务加载。

在 1.6.7 中还添加了加载新模块的能力,这可能会引起某些人的兴趣。

于 2018-02-19T21:48:59.250 回答
0

不过,自动加载或创建模块的问题可以通过 gulp-angular-filesort 之类的方法更好地解决。它确实完美无缺。

来自gulp-angular-filesort github 页面: 根据模块定义和使用情况自动对 AngularJS 应用程序文件进行排序

与 gulp-inject 结合使用,以正确的顺序注入您的 AngularJS 应用程序文件(脚本),以消除所有Uncaught Error: [$injector:modulerr]

免责声明:我不隶属于 gulp-angular-filesort,我只使用它来获得很多利润。

于 2015-09-24T07:58:54.947 回答
0

一个更好的解决方案是在创建模块时简单地进行检查。您只需要一个实用函数来添加回调。

//create a utility function to add a callback to object methods    
//here we are making it a method of the underscore or lowdash object
//but it could be added to the angular global object or anything else
_.addCallBack = function (obj, originalMethodName, callBackMethod, context){
            var fnOriginal = obj[originalMethodName],
                outcome;

            context = context || obj;

            obj[originalMethodName] = function () {
                var outcome = fnOriginal.apply(this, arguments);

                callBackMethod.apply(this, arguments);

                return outcome;
            };
};

_.addCallBack(angular, "module", function(sModuleName, asDependencies){
    if(_.contains(asDependencies, "ngRoute")){
      //your logic here
      //just loop through if you don't use underscore or lowdash
    }
});
于 2016-03-24T18:31:05.067 回答