【问题标题】:Gracefully handling AngularJS Error: $injector:nomod Module Unavailable优雅地处理 AngularJS 错误:$injector:nomod 模块不可用
【发布时间】:2015-09-22 23:37:25
【问题描述】:

我的 Angular 应用依赖于第三方 Angular 服务:

var app = angular.module("ninjaModule", ['angular-google-analytics']);

只要我的广告拦截插件关闭,应用就可以正常加载。但是,使用 angular 广告拦截器会引发 $injector:nomod 错误,无法加载整个应用程序。

我正在寻找一种方法来优雅地处理这些错误,因此无论广告拦截器如何都能加载应用程序。如果 angular-google-analytics 不存在 - 很好,这并不重要,我可以处理它或设置一些后备。但是整个应用程序崩溃的情况对我来说不是一个选择。有什么想法吗?

确切地说 - 我不想解决广告拦截器,例如通过重命名我的脚本文件。我期待一个有角度的try-catch魔术。

Plunker:http://plnkr.co/edit/sbEG6vclPidPSNGV5Bsa

【问题讨论】:

    标签: angularjs google-analytics adblock


    【解决方案1】:

    我终于让它工作了。不过,该解决方案需要一些技巧:

    1. 检查 angular-google-analytics 是否已加载
    2. 即时准备主模块的依赖关系列表 (deps)
    3. 明确使用$injector 而不是Analytics

    我仍然需要配置AnalyticsProvider,但使用$injector 应该相对容易。


    var deps = [];
    
    try {
      angular.module("angular-google-analytics"); // this throws if GA script is not loaded
      deps.push('angular-google-analytics');
    } catch(e){ console.error("GA not available", e); }
    
    angular.module('mainApp', deps)
    .run(function($rootScope, $injector) {
      try {
        Analytics = $injector.get('Analytics');
        $rootScope.trackPage = function() {
          console.log('Analytics in action!');
          Analytics.trackPage();
        }
      } catch(e) {
        $rootScope.trackPage = function(key, label) {
          console.log("Fallback in action!")
        }
      }
    })
    .controller('MyCtrl', function($rootScope, $scope) {
      $scope.message = 'Hello World!';
      $rootScope.trackPage();
    });
    

    更新的插件:http://plnkr.co/edit/Zo4RgKOybzhvJQdW2nQZ?p=preview

    【讨论】:

    • 而且思路和这个答案很相似:stackoverflow.com/a/22173678/1640299
    • 确认适用于我的应用程序。请注意,intellij Idea 会抱怨未定义分析但忽略该错误。
    【解决方案2】:

    由于angular-google-analytics 需要config 块来设置帐户,您最好的办法是将谷歌分析报告分离到您应用的单独子模块中:

    //create separate module for analytics reporting
    var reportingModule = angular.module('mainApp.reporting', [
      'angular-google-analytics'
    ])
    .config(function(AnalyticsProvider) {
      AnalyticsProvider.setAccount('UA-HELLO-GA');
    })
    .run(function(Analytics) {
      console.log('mmm.. analytics is good for you');
    });
    

    然后通过module.requires 数组将这个子模块异步注入到主模块中,以便在主模块完成引导后运行:

    var mainApp = angular.module('mainApp', [
    
    ])
    .controller('MyCtrl', function($scope) {
      $scope.message = 'Hello World!';
    });
    
    //set the dependency after app finished bootstrapping
    setTimeout(function() {
      angular.module('mainApp').requires.push('myapp.reporting');
    }, 1);
    

    这样主模块完成引导,而不会影响报告子模块错误。

    这是您 plunkr 的分叉版本:http://plnkr.co/edit/lgNZOz4MZx0FGoCOGRC9

    【讨论】:

    • 这看起来很有希望,但是angular.module() 方法没有抛出异常。它也不是从app.requires.push() 抛出的,所以 try-catch 并没有真正的帮助。
    • 实际上,所有的app.config(...)、app.factory(...)、app.value(...) 调用都是成功的(尽管它们可能是异步的),并且稍后会从 angular 的内部抛出错误。
    • 我刚刚看到您对 plunkr 的更新问题,由于我不熟悉 angular-google-analytics,我不知道设置帐户需要 config 块。这改变了事情。让我做一些研究,我会更新我的答案。
    • @PawełRychlik 请查看我的更新答案。我希望它有所帮助。
    • 嗯,感谢您的努力,但我的问题仍然存在:在关闭广告拦截器的情况下运行 plunk 会显示 Hello World,但 GA 脚本未激活 - 控制台日志未显示 :) (即使我在 index.html 中取消了 GA <script> 的注释)。
    【解决方案3】:

    接受的答案打破了gulp dependency injection,因此我对其进行了迭代以提出一种更加独立的方法(如果您依赖gulp-inject,您仍然需要手动注入此模块的脚本标签)。

    你可以添加依赖dynamically,你可以完全避免使用$injector。

    angular.module('app', [
        'your',
        'regular',
        'dependencies'
    ])
        .config(function(...) {
            /*your normal code*/
        })
        .run(function(...) {
            /*with no concern for analytics*/
        })
        //mimicking your answer for equivalence
        .controller('MyCtrl', function($rootScope) {
            if ($rootScope.Analytics)
                $rootScope.Analytics.trackPage();
        }) 
    ;
    
    
    //protect against adblockers
    try {
        //throws if not available
        angular.module('angular-google-analytics');
    
        //dynamically add the dependency
        angular.module('app').requires.push('angular-google-analytics');
    
        //set it up
        angular.module('app')
            .config(function (AnalyticsProvider) {
                AnalyticsProvider.setAccount('UA-00000000-0');
            })
            //so we dont need to use $injector
            .run(function(Analytics, $rootScope) {
                $rootScope.Analytics = Analytics;
            })
        ;
    } catch(e) { console.error('GA not available'); }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-11
      • 2015-05-15
      相关资源
      最近更新 更多