David Champion
David Champion

Reputation: 275

Loading Javascript when needed using AngularJS

I am using some JavaScript libraries that may or may not be used depending on whether a user navigates to a particular view. How can I hold off loading and still satisfy all Angular dependencies.

For example, I am using the Google maps API with ng-map (a directive for Google maps off git hub). If I load everything in HTML HEAD then it all works fine. I attempted to move the script tags into the view partial that uses ng-map but I get an error because angular.module must be passed the ng-map module. If I move only the Google API script to the view partial I get a different error that Google is not defined for ng-map.

Bottom line is, do you have to load all script/modules on the initial load?

Upvotes: 1

Views: 282

Answers (2)

Anton Savchenko
Anton Savchenko

Reputation: 1220

You should split your scripts into entry-specific modules, for that task you can use browserify with fuctor-bundle or partion-bundle for more flexibility.

That's about gathering your scripts, and about gathering angular modules (which are not the same) you can look at this answer.

Upvotes: 0

shivas
shivas

Reputation: 923

If you are using third party libraries, you can load them when needed using a lazy load option like this:

Create a service:

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

    function loader(createElement) {
        var promises = {};

        return function (url) {
            if (typeof promises[url] === 'undefined') {
                var deferred = $q.defer();
                var element = createElement(url);

                element.onload = element.onreadystatechange = function (e) {
                    $timeout(function () {
                        deferred.resolve(e);
                    });
                };
                element.onerror = function (e) {
                    $timeout(function () {
                        deferred.reject(e);
                    });
                };

                promises[url] = deferred.promise;
            }

            return promises[url];
        };
    }


    this.loadScript = loader(function (src) {
        var script = $document[0].createElement('script');

        script.src = src;

        $document[0].body.appendChild(script);
        return script;
    });


    this.loadCSS = loader(function (href) {
        var style = $document[0].createElement('link');

        style.rel = 'stylesheet';
        style.type = 'text/css';
        style.href = href;

        $document[0].head.appendChild(style);
        return style;
    });
}])

Then on your Angular Module add a service for your third party library:

.service('ckeditorService', function ($window, $q, lazyLoad) {
    this.CKEDITOR = function () {
        var deferred = $q.defer();

        if (typeof $window.CKEDITOR === "undefined") {
            lazyLoad.loadScript('lib/ckeditor/ckeditor.js').then(function () {
                deferred.resolve($window.CKEDITOR);
            }).catch(function () {
                console.log('Error loading : lib/ckeditor/ckeditor.js');
                deferred.resolve($window.CKEDITOR);
            });
        } else {
            deferred.resolve($window.CKEDITOR);
        }

        return deferred.promise;
    }

})

Then in your Controller where you want to use the service:

.controller('maintainItemDetailsController', function (ckeditorService) {

     ckeditorService.CKEDITOR().then(function (CKEDITOR) {
        self.editable = true;
        CKEDITOR.inline('description');
        CKEDITOR.inline('additional_info');
    });

})

In this example I am using the ckeditor library but in your case it will be the Google maps library

Upvotes: 1

Related Questions