41

I've just started learning Angular and following the tutorial here - http://docs.angularjs.org/tutorial/step_00

I'm downloaded the seed example from GitHub and it works great. I have a question though - if a partial view requires an external js file to be referenced, does it need to be added to the index.html file at the beginning? I want the app to be as lean as possible and only want to include the js references that are required for the present view. Is it possible to load the js files dynamically based on a view?

tempid
  • 7,838
  • 28
  • 71
  • 101

2 Answers2

42

This just worked for me. Figured I would post it for anybody else seeking the lightest-weight solution.

I have a top-level controller on the page's html tag, and a secondary controller for each partial view.

In the top-level controller I defined the following function…

$scope.loadScript = function(url, type, charset) {
    if (type===undefined) type = 'text/javascript';
    if (url) {
        var script = document.querySelector("script[src*='"+url+"']");
        if (!script) {
            var heads = document.getElementsByTagName("head");
            if (heads && heads.length) {
                var head = heads[0];
                if (head) {
                    script = document.createElement('script');
                    script.setAttribute('src', url);
                    script.setAttribute('type', type);
                    if (charset) script.setAttribute('charset', charset);
                    head.appendChild(script);
                }
            }
        }
        return script;
    }
};

So in the secondary controllers I can load the needed scripts with a call like the following…

$scope.$parent.loadScript('lib/ace/ace.js', 'text/javascript', 'utf-8');

There's a slight delay before the objects contained in the external script are available, so you'll need to verify their existence before attempting to use them.

Hope that saves somebody some time.

Ben Thielker
  • 4,104
  • 4
  • 21
  • 20
  • Thanks for the trick, very useful, with a little modification it can load css too. – Yassine Khachlek Dec 15 '15 at 14:19
  • So, once the new script is loaded into the browser, how do you bootstrap additional controllers or directives that might be contained in that script? And then do you need to execute any code to get Angular to re-process the markup? – Simon Green Jan 27 '16 at 23:04
  • 1
    I think it would be better if you return a promise that will resolve on the script onload. – alans Jan 28 '16 at 06:19
  • If it's the top controller, you can emit events like `$scope.$broadcast('scriptLoaded', { scriptName: 'foo' });` and receive it in other controllers as `$scope.$on('scriptLoaded', function..)` – Taku Dec 18 '16 at 08:37
  • This works and is just what I was looking for. Thanks! – MadHacker Feb 28 '17 at 22:21
  • You can probably use $script.js inside you loadScript. – Akshar Raaj Mar 17 '17 at 08:33
17

I just tried the https://oclazyload.readme.io/. It works out of the box.

bower install oclazyload --save

Load it in your module, and inject the required module in controller:

var myModule = angular.module('myModule', ['oc.lazyLoad'])
   .controller('myController', ['$scope', '$ocLazyLoad', '$injector',

       function($scope, $ocLazyLoad, $injector) {
           $ocLazyLoad.load(
                   ['myExtraModule.js',
                       'orAnyOtherBowerLibraryCopiedToPublicFolder.js'
                   ])
               .then(function() {
                   // Inject the loaded module
                   var myExraModule = $injector.get('myExtraModule');
               });
       }
   ]);
Kostanos
  • 9,615
  • 4
  • 51
  • 65