javascript - Dynamically loaded jQuery not defined when using inline script - Stack Overflow

Situation:jQuery is dynamically loaded together with other scripts by one file javascripts.js in the &l

Situation:

  • jQuery is dynamically loaded together with other scripts by one file javascripts.js in the <head> section of the html file
  • Each html file has it's own javascript code executed on jQuery(document).ready() in the <body> section of the html file

Problem:

  • Error: jQuery is not defined for javascript in the <body> section
  • Modifying the html file is not an option (+1000 files with same problem)

Example html file:

<html>
  <head>
    <title>JS test</title>
    <script src="javascripts.js" type="text/javascript"></script>
  </head>
<body>
  <input type="text" class="date">
  <script>
    jQuery(document).ready(function() {  // Error: jQuery not defined
      jQuery('.date').datepicker();
    });
  </script>
</body>
</html>

javascripts.js:

// Load jQuery before any other javascript file
function loadJS(src, callback) {
    var s = document.createElement('script');
    s.src = src;
    s.async = true;
    s.onreadystatechange = s.onload = function() {
        var state = s.readyState;
        console.log("state: "+state);
        if (!callback.done && (!state || /loaded|plete/.test(state))) {
            callback.done = true;
            callback();
        }
    };
    document.getElementsByTagName('head')[0].appendChild(s);
}

loadJS('javascripts/jquery-1.8.3.min.js', function() {
    var files = Array(
      'javascripts/functions.js',
      'javascripts/settings.js'
    );

    if (document.getElementsByTagName && document.createElement) {
        var head = document.getElementsByTagName('head')[0];

        for (i = 0; i < files.length; i++) {
            var script = document.createElement('script');
            script.setAttribute('type', 'text/javascript');
            script.setAttribute('src', files[i]);
            script.async = true;
            head.appendChild(script);
        }
    }
});

Situation:

  • jQuery is dynamically loaded together with other scripts by one file javascripts.js in the <head> section of the html file
  • Each html file has it's own javascript code executed on jQuery(document).ready() in the <body> section of the html file

Problem:

  • Error: jQuery is not defined for javascript in the <body> section
  • Modifying the html file is not an option (+1000 files with same problem)

Example html file:

<html>
  <head>
    <title>JS test</title>
    <script src="javascripts.js" type="text/javascript"></script>
  </head>
<body>
  <input type="text" class="date">
  <script>
    jQuery(document).ready(function() {  // Error: jQuery not defined
      jQuery('.date').datepicker();
    });
  </script>
</body>
</html>

javascripts.js:

// Load jQuery before any other javascript file
function loadJS(src, callback) {
    var s = document.createElement('script');
    s.src = src;
    s.async = true;
    s.onreadystatechange = s.onload = function() {
        var state = s.readyState;
        console.log("state: "+state);
        if (!callback.done && (!state || /loaded|plete/.test(state))) {
            callback.done = true;
            callback();
        }
    };
    document.getElementsByTagName('head')[0].appendChild(s);
}

loadJS('javascripts/jquery-1.8.3.min.js', function() {
    var files = Array(
      'javascripts/functions.js',
      'javascripts/settings.js'
    );

    if (document.getElementsByTagName && document.createElement) {
        var head = document.getElementsByTagName('head')[0];

        for (i = 0; i < files.length; i++) {
            var script = document.createElement('script');
            script.setAttribute('type', 'text/javascript');
            script.setAttribute('src', files[i]);
            script.async = true;
            head.appendChild(script);
        }
    }
});
Share Improve this question edited Mar 27, 2014 at 22:42 Jatin 3,0876 gold badges30 silver badges42 bronze badges asked Mar 27, 2014 at 15:00 Bram VerstratenBram Verstraten 1,55713 silver badges26 bronze badges 9
  • It would appear that you are loading async. If you changed this to false it would cause it to load and be available before your scripts in the page were executed. jQuery(document).ready(function() is going to fail because of the async. – CaptainBli Commented Mar 27, 2014 at 15:03
  • "+1000 files with same problem" Well, you should then really think about using any kind of templating system then. Regarding your issue, you could try to use instead: window.onload = function(){/*jQuery code here*/}; – A. Wolff Commented Mar 27, 2014 at 15:06
  • Tried switching async to false but didn't work. It has to be async because all the javascript files have to be loaded before any other script on the page must be executed. – Bram Verstraten Commented Mar 27, 2014 at 15:07
  • 1000 seriously broken pages: Modifying the HTML may be the only option. Find faster ways of modifying the HTML instead (VS global search replace etc). – iCollect.it Ltd Commented Mar 27, 2014 at 15:08
  • " It has to be async because" You mean sync right, or i didn't understand what you mean – A. Wolff Commented Mar 27, 2014 at 15:09
 |  Show 4 more ments

3 Answers 3

Reset to default 4

This is happening, as many in the ments have pointed out, because you are loading jQuery asynchronously. Asynchronous means the rest of the code is executed, and so your document-ready handler (DRH) line is running before jQuery is present in the environment.

Here's a really hacky way of resolving this. It involves making a temporary substitute of jQuery whose job is just to log the DRH callbacks until jQuery has arrived. When it does, we pass them in turn to jQuery.

JS:

//temporary jQuery substitute - just log ining DRH callbacks
function jQuery(func) {
    if (func) drh_callbacks.push(func);
    return {ready: function(func) { drh_callbacks.push(func); }};
};
var $ = jQuery, drh_callbacks = [];

//asynchronously load jQuery
setTimeout(function() {
    var scr = document.createElement('script');
    scr.src = '//ajax.googleapis./ajax/libs/jquery/1.11.0/jquery.min.js';
    document.head.appendChild(scr);
    scr.onload = function() {
        $.each(drh_callbacks, function(i, func) { $(func); });
    };
}, 2000);

HTML:

jQuery(document).ready(function() { alert('jQuery has loaded!'); });

Fiddle: http://jsfiddle/y7aE3/

Note in this example drh_callbacks is global, which is obviously bad. Ideally hook it onto a namespace or something, e.g. mynamespace.drh_callbacks.

I believe this simple solution should do the trick. The changed line in the html changes the jquery onload function to a regular function. The jquery onload function will sometimes happen before the jquery is loaded and we can't have that. It's unreliable. We need that function not to execute on page load, but AFTER the jquery has loaded.

To that end, the three lines I've added in the javascript.js are inside the code that is executed immediately after jQuery has finished loading. They test to see if the pageLoaded function has been defined (so you don't have to put one on every page, only the ones that need it) and then execute it if it's there.

Now, because the change to the HTML is simple, you can just do a regex search and replace on those 1000 files to fix them. Tools like Sublime, Eclipse or TextPad are suited for that task.

Cheers!

Example html file:

<html>
  <head>
    <title>JS test</title>
    <script src="javascripts.js" type="text/javascript"></script>
  </head>
<body>
  <input type="text" class="date">
  <script>
    function pageLoaded() { // changed
      jQuery('.date').datepicker();
    } // changed
  </script>
</body>
</html>

javascripts.js:

// Load jQuery before any other javascript file
function loadJS(src, callback) {
    var s = document.createElement('script');
    s.src = src;
    s.async = true;
    s.onreadystatechange = s.onload = function() {
        var state = s.readyState;
        console.log("state: "+state);
        if (!callback.done && (!state || /loaded|plete/.test(state))) {
            callback.done = true;
            callback();
        }
    };
    document.getElementsByTagName('head')[0].appendChild(s);
}

loadJS('javascripts/jquery-1.8.3.min.js', function() {
    var files = Array(
      'javascripts/functions.js',
      'javascripts/settings.js'
    );

    if (document.getElementsByTagName && document.createElement) {
        var head = document.getElementsByTagName('head')[0];

        for (i = 0; i < files.length; i++) {
            var script = document.createElement('script');
            script.setAttribute('type', 'text/javascript');
            script.setAttribute('src', files[i]);
            script.async = true;
            head.appendChild(script);
        }
    }
    if( typeof(pageLoaded) == "function" ){  // added
        pageLoaded();  // added
    }  // added
});

You should try following workaround to load scripts synchronously:

function loadJS(src, callback) {
    document.write('<scr'+'ipt src="'+src+'"><\/scr'+'ipt>');
    callback();
}

IMPORTANT to note: this function should be called always before DOM is fully rendered.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745221996a4617290.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信