Allan Vargas
Allan Vargas

Reputation: 69

Dynamically add scripts to my app depending on conditional

I have created a plunker to relate to my question.

I have an app with multiple pages which starts on the login page. When my app first loads it loads index.html which runs a script I have set up called config.js to which then redirects to login.html. This just manages some settings I want to use throughout my app.

In config.js I have set up window.localStorage.setItem("use_minified",true) and I want to use this in login.html to determine to use minified files or not for my application.

I had a look at a couple of questions, such as this one:

Dynamically add script tag with src that may include document.write

Which I have attempted (as you'll see in my plunker) but I am getting the error:

Uncaught Error: [$injector:modulerr] Failed to instantiate module myAppdue to: Error: [$injector:nomod] Module 'myApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.

Upvotes: 1

Views: 1339

Answers (2)

Allan Vargas
Allan Vargas

Reputation: 69

My answer:

I have kept index.html the same so that it calls config.js and redirect to login.html.

I added these to my config.js file:

function init_scripts() {
    var jsDirectory = "js";
    var jsExtension = ".js";

    if (JSON.parse(window.localStorage.config).use_minified) {
        jsDirectory = "js_min";
        jsExtension = ".min.js";
    }

    loadScripts([
        "../lib/ionic/js/ionic.bundle.js",
        "../cordova.js",
        "https://cdnjs.cloudflare.com/ajax/libs/angularjs-toaster/1.1.0/toaster.min.js",
        "/lib/ionic-datepicker-fork-ionic1/dist/ionic-datepicker.bundle.min.js",
        "/" + jsDirectory + "/app" + jsExtension,
        "/" + jsDirectory + "/page1" + jsExtension,
        "/" + jsDirectory + "/page2" + jsExtension,
        "/" + jsDirectory + "/page3" + jsExtension

    ], null);
}

function loadScripts(array, callback) {
    var loader = function(src, handler) {
        var script = document.createElement("script");
        script.src = src;
        script.onload = script.onreadystatechange = function() {
            script.onreadystatechange = script.onload = null;
            handler();
        }
        var head = document.getElementsByTagName("head")[0];
        (head || document.body).appendChild(script);
    };

    (function run() {
        if (array.length != 0) {
            loader(array.shift(), run);
        } else {
            callback && callback();
        }
    })();
}

In the <head> of my login.html I removed all <script> tags and replaced them:

<head>
   <script src="/js/config.js"></script>
   <!-- Functions found in config.js -->
   <script>
      init_scripts();
      init_stylesheets();
   </script>
</head>

This seems to be running quite nicely. I have also done a similar thing for the stylesheets, as you can see I call the function init_stylesheets(); which uses the same concept.

Upvotes: 2

reezvi
reezvi

Reputation: 44

You should use any dependency/module loader like requirejs to make your dependency loading more organized in application.

To load script dynamically in DOM, you can use a function like this -

var loadScript = function (url, callback) {
    var script = document.createElement("script");
    script.type = "text/javascript";

    if (script.readyState) {  //IE
        script.onreadystatechange = function () {
            if (script.readyState == "loaded" || script.readyState == "complete") {
                script.onreadystatechange = null;

                console.log(url + ' loaded successfully.');

                if ($.isFunction(callback)) {
                    callback();
                }
            }
        };
    } else {  //Others
        script.onload = function () {
            console.log(url + ' loaded successfully.');

            if ($.isFunction(callback)) {
                callback();
            }
        };
    }

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}

This function should reside at any script that is loaded upfront (i.e. config.js). You can avoid the second param if you don't need. It just gives you a facility to do something if you need once after the script is loaded.

Here's a demo call to script loading function using your myApp -

var myApp = angular.module('myApp', ['ionic','ionic-datepicker','ui.router','toaster','ngAnimate']);

myApp.run(function(){
  config.loadScript('yourScriptPath', null);
})
.config(function($stateProvider, $urlRouterProvider) {

    //==========================================================================//
    // Build the pages up for the application with their respective controllers //
    //==========================================================================//
    $stateProvider
    .state('login', {
        cache               : false,
        url                 : '/',
        controller          : "LoginController",
        templateUrl         : 'login.html'
    })
    .state('page1', {
        cache               : false,
        url                 : '/page1',
        controller          : "page1controller",
        templateUrl         : 'page1.html'
    })
    .state('page2', {
        cache               : false,
        url                 : '/page2',
        controller          : "page2controller",
        templateUrl         : 'page2.html'
    })
    .state('page3', {
        cache               : false,
        url                 : '/page3',
        controller          : "page3controller",
        templateUrl         : 'page3.html'
    });

    $urlRouterProvider.otherwise('/');
});

Thanks

Upvotes: 0

Related Questions