Loading jQuery plugins from third-party scripts

Published on 07 February 2015, updated on 14 February 2015, Comments

Need help with your web widget? Learn more about my profile and contact me!

Introduction

In a previous article, I’ve introduced a way to build a web widget using jQuery. One of the questions that several people asked is how to load jQuery plugins from a third-party widget. I recently had the need for this myself and I came up with a simple solution that I’m going to show in this article. Note that if your plugins support AMD and you’re willing to include a few extra kilobytes, you may consider using a tool like RequireJS. Here I’ll show you a simple do-it-yourself approach.

The problem

Quite understandably, jQuery plugins require jQuery to be present on a page in order to load properly. This is fine under normal circumstances, but when creating a third-party widget, we cannot expect jQuery to be loaded on the host page. In fact even if it is loaded, we probably won’t use it but instead load our own version of jQuery that we fully control.

To illustrate the problem we’ll create a minimal widget that just inserts Hello, World! on the host page.

Here is our host page HTML code:

<!doctype html>

<head>
  <title>Loading jQuery plugins from third-party scripts - Example 1</title>
  <meta charset="utf-8">
</head>

<body>
  <h1>Loading jQuery plugins from third-party scripts</h1>
  <h2>Example 1</h2>
  <p id="hello">Widget will write content here</p>
  <script src="widget.js"></script>
</body>

And here is the JavaScript code of our widget:

/* widget.js */
(function(window, document) {"use strict";  /* Wrap code in an IIFE */

var jQuery, $; // Localize jQuery variables

function loadScript(url, callback) {
  /* Load script from url and calls callback once it's loaded */
  var scriptTag = document.createElement('script');
  scriptTag.setAttribute("type", "text/javascript");
  scriptTag.setAttribute("src", url);
  if (typeof callback !== "undefined") {
    if (scriptTag.readyState) {
      /* For old versions of IE */
      scriptTag.onreadystatechange = function () { 
        if (this.readyState === 'complete' || this.readyState === 'loaded') {
          callback();
        }
      };
    } else {
      scriptTag.onload = callback;
    }
  }
  (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(scriptTag);
}

function main() {
  /* The main logic of our widget */
  $('#hello').html('This content comes from our widget');
}

/* Load jQuery */
loadScript("../jquery.js", function() {
  /* Restore $ and window.jQuery to their previous values and store the
     new jQuery in our local jQuery variables. */
  $ = jQuery = window.jQuery.noConflict(true);
  main(); /* Execute the main logic of our widget once jQuery is loaded */
});

}(window, document)); /* end IIFE */

Now let’s see how we can make use of a jQuery plugin to improve our widget. We’ll use a basic plugin example from the jQuery documentation:

/* plugin.js */
(function ( $ ) {
  var shade = "#556b2f";
  $.fn.greenify = function() {
    this.css( "color", shade );
    return this;
  };
}( jQuery ));

Here is our updated widget code that loads this plugins:

(function(window, document) {"use strict";  /* Wrap code in an IIFE */

var jQuery, $; // Localize jQuery variables

function loadScript(url, callback) {
  /* Same as before...  */
}

function main() {
  /* The main logic of our widget */
  $('#hello').html('This content comes from our widget').greenify();
}

/* Load jQuery */
loadScript("../jquery.js", function() {
  /* Restore $ and window.jQuery to their previous values and store the
     new jQuery in our local jQuery variables. */
  $ = jQuery = window.jQuery.noConflict(true);
  /* Load jQuery plugin and execute the main logic of our widget once the
     plugin is loaded is loaded */
  loadScript("../jquery-plugin.js", main);
});

}(window, document)); /* end IIFE */

When we load the demo page in our browser, we don’t see the expected green text. Having a look at our development console shows that there’s a problem with the jQuery variable and that the plugin is not available. For instance Firefox Developer Tools print these messages:

TypeError: $ is undefined
TypeError: $(...).html(...).greenify is not a function

Since the jQuery variable is not present on the page, the plugin code fails to execute and its functionality is unavailable.

The solution

The solution is to wrap the plugin code within a function definition. Once the plugin has loaded, we call that function from our code, passing it the jQuery object as its only argument. Here is the modified plugin code:

function initGreenifyPlugin(jQuery) {
  (function ( $ ) {
    var shade = "#556b2f";
    $.fn.greenify = function() {
      this.css( "color", shade );
      return this;
    };
  }( jQuery ));
}

And here is our widget code which now calls our plugin initializer:

/* jshint browser: true */
(function(window, document) {"use strict";  /* Wrap code in an IIFE */

var jQuery, $; // Localize jQuery variables

function loadScript(url, callback) {
  /* Same as before */
}

function main() {
  /* The main logic of our widget */
  $('#hello').html('This content comes from our widget').greenify();
}

/* Load jQuery */
loadScript("../jquery.js", function() {
  /* Restore $ and window.jQuery to their previous values and store the
     new jQuery in our local jQuery variables. */
  $ = jQuery = window.jQuery.noConflict(true);
  /* Load jQuery plugin and execute the main logic of our widget once the
     plugin is loaded is loaded */
  loadScript("../modified-jquery-plugin.js", function() {
    initGreenifyPlugin(jQuery);
    main();
  });
});

}(window, document)); /* end IIFE */

As you can see on the demo page, the plugin is now loading fine.

Conclusion

The technique I’ve presented in this article is a hack, but so far I’ve found that it works fine. I’ve used it successfully with Magnific Popup, carouFredSel, TouchSwipe and even jQuery UI. Of course it’s not ideal that we have to modify the plugin source code, but this modification can be automated using your favourite build tool.

If you want to dig deeper into the topic, I highly recommend the book Third-Party JavaScript. I found it to be a very pleasant and informative read.

Need help with your web widget? Learn more about my profile and contact me!
blog comments powered by Disqus