只要包含 JQuery,Angular 就会抛出错误

Angular throws errors whenever JQuery is included


注意

This is a link to a sample application that reproduces the issue


我在 ASP.Net 4.6 应用程序中使用 SystemJS、JSPM、Angular 和 jQuery。但是,每当我尝试在应用程序中包含 jQuery 时,我都会收到模块加载错误。

我上传了一个简单的应用程序来将问题重现到此处的保管箱:Simple App That Reproduces Issue

(你需要 Visual Studio 2015 到 运行)

基本上,在项目中有一个文件 /scripts/app/app.js 看起来像这样:

import 'jquery';
import "angular";

var ByobApp = angular.module("ByobApp", []);

当您尝试 运行 应用程序时,代码看起来像这样,您将看到这些错误(Chrome 屏幕截图):

但是,当您将代码更改为:

//import 'jquery';
import "angular";

var ByobApp = angular.module("ByobApp", []);

(注释掉 jQuery 导入)。该应用程序将正常加载。

显然 jQuery 导入有问题。但我不知道是什么!

任何帮助都会很棒。


编辑

根据评论,我将 _Layout.cshtml 更改为如下所示(包括 JQuery 和 Angular,但未尝试使用 SystemJs 加载它):

<script src="~/scripts/jspm_packages/npm/jquery@2.2.0/dist/jquery.min.js"></script>
<script src="~/scripts/jspm_packages/github/angular/bower-angular@1.4.8/angular.min.js"></script>
<script src="/scripts/jspm_packages/system.js"></script>
<script src="/scripts/config.js"></script>
<script>
    System.baseURL = "/scripts";
</script>

我让 app.js 看起来像这样:

//import 'jquery';
//import "angular";

var ByobApp = angular.module("ByobApp", []);

错误是一样的。


编辑 2

如果我改用 Zepto 库,它就可以正常工作。 Zepto 是jQuery API 的1:1 替代品,所以使用起来完全一样!

当使用模块加载 Angular 时,这种行为(不幸的是)是意料之中的。来自 initialization 的文档:

Angular initializes automatically upon DOMContentLoaded event or when the angular.js script is evaluated if at that time document.readyState is set to 'complete'.

在模块情况下,当 document.readyState'complete' 时加载 Angular。

At this point Angular looks for the ng-app directive which designates your application root. If the ng-app directive is found then Angular will:

  • load the module associated with the directive
  • ...

记住,Angular是作为app.js的依赖加载的,所以它在app.js之前执行了,即ByobApp ] 不存在!所以上面的第一步失败了,你得到了错误。

必须使用手动初始化(如 Etsitra 的评论中所建议的那样)- 将 Angular 与模块加载器 AFAIK 一起使用的唯一方法。这有效:

  • 从您的 HTML 主文件中删除 ng-app
  • 将以下内容添加到 app.js:

    angular.bootstrap(document, ['ByobApp']);
    

TLDR

它看起来像一个 angular 错误(可能特定于 1.4.8 版本和 system.js 用法)。 解决方法是bootstrap申请manually.

错误分析

问题是,当 angular 应用 bootstrap 与 ng-app:

<body ng-app="ByobApp">
    ...
</body>

应用程序代码在 angular 之前加载 jquery(使用 system.js):

import 'jquery';
import "angular";
var ByobApp = angular.module("ByobApp", []);

并且 angular 引发错误:

Uncaught Error: [$injector:modulerr]
Failed to instantiate module ByobApp due to:
Error: [$injector:nomod] Module 'ByobApp' is not available!
You either misspelled the module name or forgot to load it.
If registering a module ensure that you specify the dependencies
as the second argument.
http://errors.angularjs.org/1.4.8/$injector/nomod?p0=ByobApp

如果删除 jquery 导入或者即使我们交换 jquery 和 angular:

也能正常工作
import "angular";
import 'jquery';  // it works if jquery is second
var ByobApp = angular.module("ByobApp", []);

解决方法

解决方法是手动初始化angular应用程序:

<!-- do not include ng-app="ByobApp" here -->
<body>
    <nav class="navbar navbar-default" role="navigation">
        ...
    </nav>

    <script src="/scripts/jspm_packages/system.js"></script>
    <script src="/scripts/config.js"></script>
    <script>
        System.baseURL = "/scripts";
        System['import']('app/app').then(function() {
            // Manually bootstrap once application is loaded.
            // This code can be in the app.js as well, but it should
            // be at the end (when everything else is defined).
            angular.element(document).ready(function () {
              angular.bootstrap(document, ['ByobApp']);
            });
        });

    </script>
</body>

测试代码:

  • index_bug.html - 引发错误的版本
  • index.html - 工作版本,单击 'Home' 将消息从一个控制器发送到另一个控制器
  • app.js - 申请代码