Angular脚本加载:如何在一次调用中包含所有脚本

时间:2014-06-30 15:06:52

标签: javascript angularjs

我正在尝试创建一个脚本,其中包含所有必需的脚本,以使我的Angular应用程序正常工作但似乎不起作用:

function include(destination) {
    var e = window.document.createElement('script');
    e.setAttribute('src', destination);
    window.document.body.appendChild(e);
}

include('../Scripts/myApp/main.js');
include('../Scripts/myApp/appConfig.js');
include('../Scripts/myApp/MyAppController.js');
include('../Scripts/myApp/Service1.js');
include('../Scripts/myApp/Service2.js');

不幸的是,如果我尝试包含这样的应用程序脚本(它工作正常,它们被完美地加载到页面中),我得到一个错误,因为角度检测到我的“ng-app ='myAppName'”指令但发现没有为它声明的模块(我想是因为角度检查时脚本尚未加载)。如果我然后尝试至少将模块实例化放在由HTML页面(main.js)直接调用的脚本上,那么它会抱怨控制器,服务等不存在,如果我将它们附加到自己的应用程序中文件(app.controller(),app.factory,...)它没有抱怨,但它也没有发生。

看起来像这样加载脚本使得Angular不会执行它们,因为它们可能加载太晚或者某些东西。唯一的方法是设置一个脚本标签来调用HTML上的脚本。

但是我觉得我错过了一些东西,有一种方法可以做到这一点,我只是看不到它。

有人知道如何通过调用其中一个来加载所有必需的脚本吗?在角度应用程序配置上有什么东西可以设置为这样吗?

看起来太脏了,不能打这么多电话,而且性能也不好。

我已经检查过有一种名为Yeoman的东西,但它看起来像我想要的那么大,然后我看到了RequireJS,但我不确定这是我真正想要的,并且再次不确定我是否只想安装另一个库这个。最后,我已经看到在应用程序配置中你可以设置查找视图的位置,甚至是加载控制器的方法(我想,我现在不确定任何东西,我的脑袋是如此头晕)所以我在想也许Angular已经做了一些看起来很自然的东西,将脚本加入到一个?

非常感谢。

2 个答案:

答案 0 :(得分:3)

这是因为您的脚本是异步加载的,而angular正在加载页面时同步编译文档(因为我在脚本中包含了angular.js,因为我没有看到它以上)。在这种情况下,您必须手动引导应用程序,因为在使用RequireJS时您也必须这样做。这是一个例子......因为你没有使用像RequireJS这样的库,所以我也放了一个hacky计数器来查看当所有脚本加载完所有脚本加载到回调和引导角度时:

function include(destination) {
    var e = window.document.createElement('script');
    e.setAttribute('src', destination);
    //IE detect when script has fully loaded... Increase number of loaded scripts and
    //call bootstrap if all have loaded.
    e.onreadystatechange = function () {
        if (newjs.readyState === "loaded" || newjs.readyState === "complete") {
            e.onreadystatechange = null;
            loadedScripts++;
        }

        if (loadedScripts === numScripts) {
            bootstrapAngular("myAppName");
        }
    }

    //Other browsers. Same logic as above - Increase scripts loaded and call bootstrap when complete
    e.onload = function () {
        loadedScripts++;
        if (loadedScripts === numScripts) {
            bootstrapAngular("myAppName");
        }
    }
    window.document.body.appendChild(e);
}

//5 scripts being loaded
var numScripts = 5;
//0 currently loaded
var loadedScripts = 0;
include('../Scripts/myApp/main.js');
include('../Scripts/myApp/appConfig.js');
include('../Scripts/myApp/MyAppController.js');
include('../Scripts/myApp/Service1.js');
include('../Scripts/myApp/Service2.js');

function bootstrapAngular(appName) {
    //Assuming you are putting ng-app at document level... Change to be your specific element.
    angular.bootstrap(document, [appName]);
}

上面的解决方案有点hacky,因为我们正在跟踪已加载的所有脚本。这就是像RequireJS这样的库可以很好地播放的地方,因为它会在你想要的脚本被加载时调用你的回调函数。一个例子是:

require(['angular', 'jquery', 'appConfig', 'MyAppController', 'Service1', 'Service2'], function (ng, $) {
    //bootstrap when all is ready
    $(function () {
        ng.bootstrap(document, ["myAppName"]);
    });
});

答案 1 :(得分:2)

如果您正在使用AngularJS(或任何类似的高级框架),那么您肯定有时间了解模块加载。当您开始构建更多模块并开始处理更复杂的依赖链时,快速注入<script>标记会变得站不住脚。

RequireJS是一个很棒的套餐,可以在阳光下做任何事情。这里的tutorial on using the two together看起来很不错。 Browserify是一个类似的库,可让您使用NPM管理依赖项。它比RequireJS稍微简单一点,这对你来说可能是一个加分。这是tutorial that looks decent

RequireJS和Browserify都带有命令行构建工具,这很棒,因为当您准备好将应用程序部署到服务器时,它们可以将所有源代码合并到一个文件中。

但是,我应该警告你,这些东西并不容易。学习曲线相当陡峭。但是,很有可能,这是你迟早需要学习的东西。