Trung Tran
Trung Tran

Reputation: 13721

jQuery is not a function in anonymous function

I am trying to write an anonymous javascript function that dynamically loads jquery and angular. However, when I run the function I keep getting 'jQuery is not a function'. Can someone help? Here is my code:

(function() {

  var jQuery;
  var jquery_tag = document.createElement('script');
  var angular_tag = document.createElement('script');

  jquery_tag.setAttribute("type", "text/javascript");
  jquery_tag.setAttribute("src", "https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js");

  angular_tag.setAttribute("type", "text/javascript");
  angular_tag.setAttribute("src", "https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js");

  jquery_tag.onload = scriptLoadHandler;
  angular_tag.onload = scriptLoadHandler;

  (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(jquery_tag);
  (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(angular_tag);


  function scriptLoadHandler() {
    jQuery = window.jQuery
    main();
  }

  function main() {
    jQuery(document).ready(function($) {
      alert('yo'); //this runs
    });
  }

})();

Here is my fiddle:

https://jsfiddle.net/p7jcofx1/4/

Thanks in advance!

Upvotes: 0

Views: 245

Answers (2)

apokryfos
apokryfos

Reputation: 40673

From the angular documentation here

To use jQuery, simply ensure it is loaded before the angular.js file. You can also use the ngJq directive to specify that jqlite should be used over jQuery, or to use a specific version of jQuery if multiple versions exist on the page.

You can achieve this using the following:

  var jquery_tag = document.createElement('script');          

  jquery_tag.setAttribute("type", "text/javascript");
  jquery_tag.setAttribute("src", "https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js");          

  jquery_tag.onload = jQueryLoadedHandler;    

  (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(jquery_tag);      


  function jQueryLoadedHandler() {
    //Load angular after jQuery 
    var angular_tag = document.createElement('script');
    angular_tag.setAttribute("type", "text/javascript");
    angular_tag.setAttribute("src", "https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js");
    angular_tag.onload = angularLoadedHandler;
    (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(angular_tag);
  }

  function angularLoadedHandler() {         
      main(); //Both jQuery and angular should be loaded
  }

  function main() {
    jQuery(document).ready(function($) {
      alert('yo'); //this runs
    });
  }

Updated fiddle

Note: This is a suggestion in the case you want angular.js to use jQuery. If you don't mind it using jqLite then this is not necessary and the accepted answer should work just fine.

Upvotes: 1

Rick Hitchcock
Rick Hitchcock

Reputation: 35670

scriptLoadHandler() will run two times based on this code:

jquery_tag.onload = scriptLoadHandler;
angular_tag.onload = scriptLoadHandler;

Even though the Angular code is listed after the jQuery code, it could load first, making window.jQuery undefined in scriptLoadHandler, and causing jQuery(document) to fail in main().

You can prevent this by updating scriptLoadHandler as follows:

function scriptLoadHandler() {
  if(window.jQuery) {
    jQuery = window.jQuery
    main();
  }
}

Upvotes: 3

Related Questions