Building a Javascript Embedded Widget

As primarily an API / backend coder in recent years I’ve always thought that Javascript looks amazing when it works (and making it work when it seems such an ambiguous language is half the battle). However, recently I’ve had reason to write a lot more Javascript (and learn a lot along the way!), let’s start with the widget I’ve built.

I’m currently working with Kyero on their data portal, you can read more about what we’re doing and why, but here I want to talk about some of the things we’ve done…

The Challenge: Allow customers to embed a short script in their website to pull in useful content from the vast amount of data Kyero has in an easily readable format

NOTE: I’m learning this as I go, I’ve never been a Javascript developer! Feel free to tell me if I can improve this

Widget: Getting Started – Local jQuery

Kyero’s database is huge and full of numbers, and I’m fortunate to be working with people who know exactly how to extract in JSON format that I can pickup over an AJAX request.

For that I’m going to need jQuery, even if the customer isn’t running jQuery on their site, so we load a locally scoped copy before we do anything…

(function() {
  var jQuery;

  /******** Load jQuery if not present *********/
  if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.11.3') {
    var script_tag = document.createElement('script');
    script_tag.setAttribute("type", "text/javascript");
    script_tag.setAttribute("src",
      "https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js");
    if (script_tag.readyState) {
      script_tag.onreadystatechange = function() { // For old versions of IE
        if (this.readyState == 'complete' || this.readyState == 'loaded') {
          scriptLoadHandler();
        }
      };
    } else {
      script_tag.onload = scriptLoadHandler;
    }
    // Try to find the head, otherwise default to the documentElement
    (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
  } else {
    // The jQuery version on the window is the one we want to use
    jQuery = window.jQuery;
    main();
  }

  /******** Called once jQuery has loaded ******/
  function scriptLoadHandler() {
    // Restore $ and window.jQuery to their previous values and store the
    // new jQuery in our local jQuery variable
    jQuery = window.jQuery.noConflict(true);
    // Call our main function
    main();
  }
  function main() {
    // Most of what we want to do will go in here, for once we've got jQuery loaded
  }
});

Widget Embed Code

And we’ll call our widget with this HTML (this is what we’ll be providing to customers):

<div id="kyero-widget">
</div>
<script type="text/javascript"  id="kyero-widget-js"
        src="/path/to/external/js/kyero-widget.js"
        data-locale="en"
        data-location="barcelona"
        data-elements="Sun,Aeroplane"
        async
        >
</script>

The data attributes here tell us which language, location and elements we want in the widget, allowing the customer a certain level of configuration.

Widget Styling

That’s great, by the time we get to run the main function, we’ve got jQuery loaded and can start to do some real work.

First things first, let’s load in the Font Awesome css stack, and our css:

function main() {
  jQuery("<link/>", {
     rel: "stylesheet",
     type: "text/css",
     href: "https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css"
  }).appendTo("head");
  jQuery("<link>", {
     rel: "stylesheet",
     type: "text/css",
     href: "https://our-css-in-a-CDN.min.css"
  }).appendTo("head");

...
}

Sticking with main(), we then want to start our real work once the DOM is fully loaded:

jQuery(document).ready(function($) {

   // Put a temporary message on the Kyero-widget div
   jQuery('#kyero-widget').html("Data currently unavailable");

   // Grab the location to be passed to our AJAX request
   var location = document.getElementById('kyero-widget-js').getAttribute('data-location');
}

We’re good to go, we’ve got our styles and our locations.

Fetching the Widget JSON

The JSON will tell us which colour to use for each element and which Font Awesome icon to put along side it. We’re going to host several thousand JSON files all named according to the location in S3 to be served by CloudFront CDN.

Because we’re fetching these from off domain we can’t just get a JSON, it has be JSONP (JSON with Padding) to get around the security restrictions (if we were hosting them ourselves I believe we could use CORS but putting it on S3 removes this option).

So we do the following:

jQuery.ajax({
   type: 'GET',
   url: "https://path-to-our-json-storage/widget-data-"+location+".json",
   async: true,
   contentType: "application/json",
   dataType: 'jsonp'
});

Now JSONP operates on a callback, so we’ve wrapped all our JSON files in the following when storing them:

JsonWrapping (
   // JSON goes here
)

This means that when the data comes back the JsonWrapping function (that sits outside of main() ) will run, to go through the JSON, display elements chosen by the user (data-elements) in a particular colour with a particular icon. It’s pretty impressive!

I’ll leave you with the property data for Barcelona (it gets a lot of sunshine doesn’t it) 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.