Download script with dynamic src using Angular

こ雲淡風輕ζ 提交于 2019-12-07 19:43:21

问题


Angular provides ways to dynamically load templates with dynamic names via ng-include. Inline JS and CSS in that partial will load fine, but there is not a good way to download scripts with dynamic urls. We needed to download scripts, relative to the path of the .html partial calling them. (i.e. we had a directory with a file to include, and wanted the .html file to declare the scripts etc. it needed itself).

As opposed to this question, which is loading a script with a static src in a dynamically included partial, I want to include dynamically create the src for a script in a dynamically included partial, using either interpolation or running it through and angular function.

For example, I may be dynamically loading a partial into my app, from a directory in which there are several other resources that partial relies on. Instead of downloading all the files individually, I want to leave that logic in the partial. I realize that the browser cannot do this, so I'll use ng-src and allow Angular to do the heavy lifting here. Instead of parsing every script src tag relative to the partial, so I'm going to use a function to generate the urls, like so:

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

How do I do it?


回答1:


Here is a gist

Note that this will override the native script directive in angular (which checks for templates in your script tags). You could rename the directive, but we didn't need that functionality (we were injecting these services / directives into a newly bootstrapped app on the page anyway).

This assumes you have some way of downloading scripts dynamically. We are using $script, but jquery or whatever would work too, just update the service accordingly.

Instead of using what is below, which uses a function prefixUrl, you could easily rewrite the script directive to prefix the url itself (via attrs.ngSrc) without relying on the function.

I've added an event 'WidgetContentLoaded' (easy to change) that will fire once all the scripts are downloaded.

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);
            }
        }
    };
});

And your 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>


来源:https://stackoverflow.com/questions/22522237/download-script-with-dynamic-src-using-angular

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!