0

I'm trying to dynamically load some jQuery libraries into the document head.

<head>
  <script src="../js/jQuery.js"></script> 
  <script src="../js/App.js"></script>
</head>

jQuery.js looks like this:

(function() {

  /*
   * load all jQuery components
   *
   * @private
   */

  var head = document.getElementsByTagName('head')[0];

  var components = [];

  var jQuery = document.createElement('script');
  jQuery.type = 'text/javascript';
  jQuery.src = 'http://' + location.host + '/js/jquery-1.8.2.min.js';
  components.push(jQuery);

  var jQueryMobile = document.createElement('script');
  jQueryMobile.type = 'text/javascript';
  jQueryMobile.src = 'http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js';
  components.push(jQueryMobile);

  var jQueryMobileCSS = document.createElement('link');
  jQueryMobileCSS.type = 'text/css';
  jQueryMobileCSS.href = 'http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css';
  components.push(jQueryMobileCSS);

  var meta = document.createElement('meta');
  meta.name = 'viewport';
  meta.content = 'width=device-width, initial-scale=1';
  components.push(meta);

  components.forEach( function( component ) {
    head.appendChild( component );
  });

  // EDIT - FIX:
  var App = document.createElement('script');
  jQueryMobile.type = 'text/javascript';
  jQueryMobile.src = 'http://' + location.host + '/js/App.js';

  jQuery.onload = function() {
    head.appendChild(App);
  };

})();

The console.log shows that the head object contains the script tags loading the jQuery libraries. App.js requires jQuery but is throwing an error stating that jQuery is not defined. What am I missing?

ubiQ
  • 791
  • 2
  • 7
  • 17
  • 1
    Why not load App.js via the same technique? – Pointy May 02 '13 at 13:42
  • Initially for sake of clarity. I've just tried this and now Chrome is giving me the error that $ is not defined from localhost:15. I don't know where this is being thrown because App.js uses $ on line 13 to load in the title and some css and these show up in the head object. – ubiQ May 02 '13 at 13:47

3 Answers3

2

App.js is trying to execute before the dependencies are completely loaded. You should add a callback function inside the jQuery.js file that will load App.js AFTER the other libraries have loaded.

Joshua
  • 3,615
  • 1
  • 26
  • 32
  • 1
    How can i detect when the dependancies have been loaded? – ubiQ May 02 '13 at 13:59
  • Listen for the `load` event of the new script element – Ian May 02 '13 at 14:05
  • @ubiQ great question. Not an easy answer unfortunately. There are many methods to do this. One right off since you're using jQuery is to try the Deferreds method: http://api.jquery.com/deferred.done/ – Joshua May 02 '13 at 14:35
0

Your App.js is loading faster than your jQuery library and so it cannot find jQuery. You should just indcude your JS at the bottom of your HTML before the closing </body> tag instead of creating these elements dynamically in the head, e.g:

    <script src="http://hostexample.com/js/jquery-1.8.2.min.js"></script> 
    <script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script> 
    <script src="../js/App.js"></script>  
</body>

This will ensure that jQuery is loaded before you use it.

Check this link out: JavaScript - How do I make sure a jQuery is loaded?.

It offers both an explanation as to why you should do it the way I have suggested and a (nasty) solution to the way you have done it if you still choose to do it like this.

Community
  • 1
  • 1
Matt Derrick
  • 5,674
  • 2
  • 36
  • 52
  • Down vote why? I gave a perfect solution to his current problem along with a better, industry recognised, alternative. – Matt Derrick May 02 '13 at 14:08
  • I'm trying to use the technique mentioned here providing a recursive function to detect jQuery but jQuery never gets detected and i overflow the stack. – ubiQ May 02 '13 at 14:17
  • is jQuery definitely on the page and exists? In console try log $ to see if it exists after page load... – Matt Derrick May 02 '13 at 14:20
  • I'm now running it off a callback on the onload event of jQuery so loading the App.js now works. I have code in the body that is dependant on $ and runs before it gets loaded so this is now causing '$ is not defined' to be thrown. Trying to figure out if I can block the body until scripts are loaded? – ubiQ May 02 '13 at 14:30
  • 1
    Here is a fiddle to listen to the load event using pure JS (no jQuery as it won't be loaded yet) http://jsfiddle.net/4dKae/. You need to put the scripts at the bottom of the page, or, wrap all your JS in $('document').ready(function(){ //Do stuff }); This only runs any JS AFTER the entire body has loaded. You should NEVER block the body from loading, this should be always loaded first, followed by scripts. – Matt Derrick May 02 '13 at 14:37
  • Alas if you do want to block the body from loading, just insert the scripts in the head like you normally would (not via this asynchronous method you are using) and it will block the body form loading until scripts have loaded. – Matt Derrick May 02 '13 at 14:44
  • The issue is that scripts in the body use $. I want to load these scripts into the head dynamically so that I can upgrade the mobile app easily. The app consists of many html documents which each load and require jquery and jqueryMobile. – ubiQ May 02 '13 at 14:48
-1

That's because you add the jQuery script tag at the end of the header, after you app.js. So your html look like

If app.js need jquery, it is loaded befor jQuery, so it cant find what it need.

Instead of head.appendChild( component ); try :

head.insertBefore(component, head.getElementsByTagName('script')[head.getElementsByTagName('script').length - 1])

Something like that should work.

Karl-André Gagnon
  • 33,662
  • 5
  • 50
  • 75