使用Angular下载带有动态src的脚本

时间:2014-03-20 02:24:55

标签: javascript angularjs lazy-loading

Angular提供的是通过ng-include动态加载具有动态名称的模板。部分内联JS和CSS将加载正常,但没有一种好方法下载动态URL脚本。我们需要下载相对于.html部分调用它们的路径的脚本。 (即我们有一个包含文件的目录,并希望.html文件声明它自己需要的脚本等。)

与在动态包含的部分中加载带有静态src的脚本的this question相反,我想包括动态创建动态包含的部分中的脚本的src,使用插值或运行它通过角度函数。

例如,我可能会动态地将部分加载到我的应用程序中,从一个目录中,其中有一些部分依赖的其他资源。我没有单独下载所有文件,而是希望将该逻辑留在局部。我意识到浏览器无法做到这一点,所以我将使用ng-src并允许Angular在这里进行繁重的工作。而不是相对于部分解析每个脚本src标记,所以我将使用函数来生成URL,如下所示:

<script type="application/javascript" ng-src="prefixUrl('myUrl.js')"></script>

我该怎么做?

1 个答案:

答案 0 :(得分:0)

Here is a gist

请注意,这将覆盖angular中的本机脚本指令(它会检查脚本标记中的模板)。您可以重命名该指令,但我们并不需要该功能(我们无论如何都将这些服务/指令注入到页面上新引导的应用程序中。)

这假设您有一些动态下载脚本的方法。我们使用的是$ script,但是jquery或其他什么都可以工作,只需相应地更新服务。

您可以轻松地重写脚本指令,以便在不依赖函数的情况下为url本身(通过attrs.ngSrc)添加前缀,而不是使用下面的函数prefixUrl。

我添加了一个活动&#39; WidgetContentLoaded&#39;下载所有脚本后将触发(易于更改)。

的Javascript

angular.module('myApp')
.run(function ($rootScope) {
    $rootScope.mixin = function(urls) {

        if (angular.isUndefined(urls) || urls == '') {
            return $q.when('no mixin url');
        }

        var deferred = $q.defer();

        //timeout our requests at 5 seconds
        var timeoutPromise = $timeout(function() { deferred.reject(null) }, 5000);

        //assume that $script or some other way of downloading scripts is present
        $script(urls, function() {
            $timeout.cancel(timeoutPromise);
            $rootScope.$safeApply(deferred.resolve(urls));
        });

        return deferred.promise;
    };

    $document.on('WidgetContentLoaded', function () {
        //put more interesting logic here... this is like $(document).ready() but for your included partial
        console.log('yay we loaded your scripts');
    });

})
.service('lazyScripts', ['$q', '$timeout', '$document', function ($q, $timeout, $document) {

    var promises = [];

    this.register = function (url) {
        promises.push($clotho.extensions.mixin(url));
    };

    $timeout(function() {
        $q.all(promises).then(function() {
            //broadcast event
            $document.triggerHandler('WidgetContentLoaded');
        })
    });
}])
.directive('script', function($parse, $rootScope) {
    return {
        restrict: 'E',
        terminal: true,
        compile: function(element, attr) {
            if (attr.ngSrc) {
                var scriptUrl = $parse(attr.ngSrc)($rootScope);
                 lazyScripts.register(scriptUrl);
            }
        }
    };
});

和你的HTML

<script type="application/javascript" ng-src="prefixUrl('inlineCalledScript.js')"></script>

<style type="text/css">
    .greenListItem {
        color: #44bb44;
    }
</style>

<ul>
    <li>This is a dynamically loaded template.</li>
    <li>Note that angular must already be bootstrapped, with the new script directive above. This will not work in your index.html file</li>
    <li class="greenListItem">Inline CSS works!</li>
</ul>

<!-- this would work without problems -->
<div ng-include="prefixUrl('anotherPartial.html')"></div>