JavaScript Libraries

Write less, do more. - jQuery slogan

In this chapter, we will use jQuery, the most popular JavaScript library in history, to build a dynamic web application that generates reports of municipal data.

Libraries and Their Interfaces

Libraries are pre-built code that is organized in such a way that all sorts of different programs can import and use the code. They can improve the quality and reliability of your codebase. This improvement effect occurs because because open-source libraries are generally the work product of many minds who have already considered a problem from many perspectives. Libraries can also speed up application development time. Code you can immediately use is code you didn’t have to write (just don’t forget about software bloat).

Libraries can be used off-the-shelf like this because they provide interfaces. Remember how we used the Bootstrap library and to make beautiful, responsive pages in Part 3? We imported its pre-built CSS and JavaScript into our webpages with link and script tags, then used its CSS classes to add styling. CSS classes are how Bootstrap exposes its functionality, i.e. CSS classes are Bootstrap’s interface.

We will now use the jQuery library. Its simple interface makes it easy to dynamically change content and add user interactivity to our webpages.

Libraries expose their functionality via interfaces

The jQuery Library

The jQuery function is for DOM manipulation.

jQuery is written in JavaScript. You can import it into an HTML document with the following line of code:

<script src="https://code.jquery.com/jquery-3.3.1.js"></script>

Once the import is complete, a global jQuery function is available. This jQuery function is the jQuery library’s interface. If you go to jQuery.com and open up the JavaScript console, you can examine it using the console.dir(jQuery); statement.

You can use this jQuery function to start grabbing existing DOM nodes (identifying them with CSS selectors) and manipulating them. You can erase DOM nodes, read them, change their content, and alter their styling. You can also create new DOM nodes and attach them to existing nodes. A brief sample:

const $body = jQuery("body");

$body.html("<h1>No war but class war!</h1>"");

$body.css("background", "pink");

Pretty handy, right? This is a much friendlier interface than the built-in document Web API. jQuery is acting like a wrapper around all those unwieldy long document.getElementById('#why-did-i-make-this-id-so-long') calls. jQuery is saying, “We all know which element you want, dammit! Take it and do stuff with it!” But don’t be fooled. If you look at jQuery’s source code, you will find that jQuery’s jQuery function is making heavy use of the browser’s document API when you call it.

What else can we do with this jQuery function? We know that it is a library built primarily for DOM manipulation, but what other functionalities are implemented in this jQuery API (Application Programming Interface)?

The jQuery object: Where Additional Functionality Lives

Do you remember that functions in JavaScript are also objects?

Actually, functions are objects first, and functions second. Under the covers, functions are just objects that became callable.

So the jQuery function is also an object. This has exciting implications for building an interface. New key value pairs can be attached to jQuery by writing code like:

jQuery.author = function(){
    alert("Kevin Moore");
}

Or you could add modules of new code by doing something like:

jQuery.backgrounds = {
    red: function(){ return "rgb(255, 0, 0)"; },
    green: function(){ return "rgb(0, 255, 0)"; },
    blue: function() { return rgb(0, 0, 255)}
}

The jQuery library has made heavy use of the fact that JavaScript objects are so easily extensible. There are now a variety of different modules. In this chapter, we will use jQuery’s HTTP requests module. While that module is located at jQuery.ajax, we will use one of the shorthand methods jQuery conveniently places on the global object - jquery.getJSON, a function which takes a URL and callback function as arguments.

This easy extensibility of the jQuery object engenders the creation of plugins, which is third-party code that adds even more functionality to the object. There is a rich jQuery plugin ecosystem.

If you browse the “API documentation” on jQuery.com or do a search for “jquery cheatsheets”, you can quickly grasp the breadth of jQuery’s functionality as a JavaScript library.

jQuery is $

jQuery is an awkward thing to write, so jQuery is aliased to $. Confirm this in the JavaScript console on jquery.com:

jQuery === $;  // returns true

So you can say $('.css-class') instead of jQuery('.css-class'). You can say $.getJSON instead of jQuery.getJSON. It’s also common, when creating variables that bind to jQuery DOM objects, to put a $ at the beginning of the variable names. This is why $body was named the way it was in const $body = jQuery("body");.

Let’s get to work!

Assignment: Report Generator

It’s Friday morning. It’s the end of your first week at CityBucket. You’re looking forward to a well-earned Friday night. You swivel and watch the sunrise through the bamboo blinds. You had a salad for dinner last night. Your eyes are beginning to drift close. The song of tonight’s pizza is reaching a crescendo in your ears. You hear the room’s door open behind you.

The CEO and the Team Lead are back. With them is a third person, The Designer, who was hired yesterday.

CEO: Hey hey! Good work this week. I saw your initial webpages. Team Lead said the code looked good, too!

Team Lead: grumbles something about “testing”

You: Thanks! It was fun to build. Team Lead is a helpful mentor.

CEO: And you remember The Designer!

You and The Designer nod at each other politely.

CEO: Alright, down to business.

Our clients are all municipal governments. They have information about all kinds of stuff - transportation and communication infrastructure, for example. One of their commons requests is for ways to communicate information to the people in their community.

You: A noble goal.

CEO: And so Team Lead and I put our heads together and came up with an idea for a new client application - a DYNAMIC REPORT GENERATOR.

It will be pretty simple. No logins or anything. Just a simple webpage that shows all kinds of reports. We will use a standardized template and simple standardized data structure

Team Lead: It’s a website with just one HTML page (also known as a “view” or a “template”). The browser will load the HTML view, which has empty DOM nodes in it. Then use JavaScript and jQuery to load some report JSON. Stuff that data in some DOM nodes, and attach them to the page.

We will use URL query parameters to determine which report you load.

The Designer: This is what the pages look like:

The Report view for two different JSON files.

You: Those look great. Blue and white – like a metro government sign!

The Designer: Exactly. That’s straight blue, just #0000ff. I built this with the Bootstrap framework in mind, so go ahead and use it.

Team Lead: You should only need the one Bootstrap CSS file. And let’s host the library locally this time, at least for development purposes. The Internet has been slow here today. If you have your browser cache disabled when the developer console is open, you’re going to have to keep importing jQuery from a CDN the whole time.

You: That makes sense. Do you want me to use a package manager or just curl the files?

Team Lead: For today, let’s just curl the files.

Team Lead: Let’s talk about project organization. At the root-level, I think you should have two folders and three files. This is what your file structure will look like. Does this make sense?

Put your library files in `lib` and your JSON in `data`.

You: Once I download jquery.js and bootstrap.css, put them in the lib folder. Put the JSON files in the data folder.

Team Lead: Indeed. You can just use the following as a sample communications.json file:

{
  "meta": {
    "municipal_body": "Marion County",
    "title": "Communications Report"
  },
  "data": [
    {
      "label": "Broadband Penetration",
      "value": "63% (low)"
    },
    {
      "label": "Radio Stations in Area",
      "value": 11
    },
    {
      "label": "Number of Weekly Newsletters",
      "value": 5
    }
  ]
}

You: Oh yes, I see how this data structure should fit into this page. There are two top-level keys - meta and data. I can take the metadata and use jQuery to add a title to the report body.

Team Lead: Yes, and then the actual data is organized as an array or report row data. Each row has a label and a value. So long as we are following this simple format in our JSON files, we can create infinitely many reports with just one HTML file and some jQuery.

You: I can just split the table into two top-level container divs - one for the jumbotron Meta information and one for the Report data. Then use jQuery to pull in the data. Then use jQuery to add the governmental (municipal) body and the report title into Title div.

You: Then I will iterate over the report’s data objects. For each object, I will create a Bootstrap row and attach it to the .Report.

The Designer: That is what I was thinking, too.

You: The DOM will end up looking something like this for each report:

The Report DOM, once all the data has been added.

Team Lead: This sounds exactly right. In order to make sure we’ve communicated correctly, here’s what the README.md should like:

# CityBucket Report Generator  

Git clone this repository. From it's root directory, run
`python -m http.server`. You should then be able to view
the page at http://localhost:8000/view.html

For demo purposes, we have transportation and communication
reports available. The default view shows the Communication
Report. If you wish to see the Transportation report, add the
`?report=transportation` query parameter to the URL, i.e. go
to http://localhost:8000/view.html?report=transportation.

You: Oh ok, we are using URL query parameters to determine which report we are loading?

Team Lead: Yes. The report query parameter will correspond to the name of the .json file. So if the query parameter is education, the JavaScript should try to load a file located at data/education.json.

You: What if the JSON file doesn’t exist in data?

Team Lead: Let’s not worry about that for today. Although you’re going to create a couple of JSON mock files for testing and development, we have a vision for this product where we have a separate server pumping out report JSON files that we will programmatically insert into the data folder. But that’s the long-term view. Today, we just want to build the plumbing.

CityBucket dreams of a data report generator

You: Got it, boss. I’ll get this to you by the end of today. I’m going to call the application report-generator-client since this is just a client-side application. You should be able to see a demo at http://<YOUR-GITHUB-NAME.github.io/report-generator-client/view.html?report=communication by the end of the day. I will also have a report set up for ?report=transportation

Team Lead: exits room, fearing you’re after their job

The Designer: give you a thumbs up, exits

CEO: …wanna do some cocaine? We got a bunch of VC money last week.

You: It’s… it’s… 9AM….

CEO: Haha, just uhhh testing you. exits

Hmmm.

Making a Plan

Did you notice that there wasn’t a Making A Plan section in the last chapter? Naughty, naughty! Let’s make a plan.

We have a good idea of what the Team Lead is thinking from the file structure and details they supplied us with. The data is sequestered in the data folder. The libraries will live in the data folder. The real code that we have to think about is the HTML and JavaScript. The CSS side of things should be easy enough – the view is very simple. Bootstrap and some custom CSS should make this part easy.

So let’s think about the view.html file (since that’s what we’ll be loading at localhost:8000/view.html).

Break it into boxes.

This is what we imagine the process looking like when we load view.html and the code runs:

  1. Load the initial HTML file. This file will import all of the library files and custom styling.
  2. The browser will create some initially empty DOM elements for the report title and report rows.
  3. The HTML file imports and runs our custom controller.js file.

OK, so now we will have all of our code loaded. We are just missing data… and a report. controller.js will take care of both:

  1. Look at the URL query string to determine which .json file to load. 2. Use jQuery to load that JSON file.
  2. Use jQuery to grab the empty title and report DIVs.
  3. Use jQuery to add the title data to the DOM.
  4. Loop over the data array. For each data object, create a Bootstrap row, then interpolate the label and value into two separate Bootstrap columns.

This is enough conceptual work. Let’s write the code!

Write the Code

1. File Setup

Go to GitHub.com and create a repository called report-generator-client. Then drop into your Terminal application:

git clone https://github.com/<YOUR-GITHUB-NAME>/report-generator-client

cd report-generator-client

mkdir data lib  

touch README.md view.html styles.css controller.js

git add .

git commit -m "Initial file structure."

2. curling The Libraries

Now go collect those library files. You’re going to get those files using curl, a command line utility for retrieving data. Simple put: go find places where Bootstrap.css and jquery.js files exist (their documentation will always tell you where you can find or download the code) and then curl them onto your computer and into files as follows:

cd lib

curl https://code.jquery.com/jquery-3.3.1.js > jquery.js

curl https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.css > bootstrap.css

You should now have files at lib/jquery.js and lib/bootstrap.css. Add them to your git repo:

cd ..

git status

git add lib

git commit -m "Added jquery.js and bootstrap.css library files"

3. Create The Mock JSON files

Now create the mock JSON files in the data folder. Here is communication.json:

{
  "meta": {
    "municipal_body": "Marion County",
    "title": "Communications Report"
  },
  "data": [
    {
      "label": "Broadband Penetration",
      "value": "63% (low)"
    },
    {
      "label": "Radio Stations in Area",
      "value": 11
    },
    {
      "label": "Number of Weekly Newsletters",
      "value": 5
    }
  ]
}

Here is transportation.json:

{
  "meta": {
    "municipal_body": "Marion County",
    "title": "Transportation Report"
  },
  "data": [
    {
      "label": "Dirt roads",
      "value": "37 miles"
    },
    {
      "label": "Paved Roads",
      "value": "87 miles"
    },
    {
      "label": "Moving violations issued (year-to-date))",
      "value": 332
    }
  ]
}

Save and commit these:

    git status
    git add data
    git status
    git commit -m "Mock JSON data."

4. Building the template: view.html

The template is almost entirely boilerplate and imports. The empty DOM nodes you will use in your JavaScript look like this:

<div class="Meta jumbotron">
  <h2 class="Meta__Government"></h2>
  <h1 class="Meta__Title"></h2>
</div>
<div class="Report container">
</div>

Here’s how the entire file should look:

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Import Bootstrap CSS. Can  also set href to https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.css if no local copy. -->
    <link rel="stylesheet" href="lib/bootstrap.css">

    <!-- Import our custom CSS -->
    <link rel="stylesheet" href="styles.css">

    <title>CityBucket</title>
  </head>
  <body>

    <!-- The report template. -->
    <div class="Meta jumbotron">
      <h2 class="Meta__Government"></h2>
      <h1 class="Meta__Title"></h2>
    </div>
    <div class="Report container">
    </div>

    <!-- Import jQuery. Can also set src to https://code.jquery.com/jquery-3.3.1.js if no local copy. -->
    <script src="lib/jquery.js"></script>

    <!-- Import custom report generator code -->
    <script src="controller.js"></script>
  </body>
</html>

Test, Iterate

This is a good point to go ahead and run the local development server with python -m http.server. You want to make sure you have your HTML elements and imports in working order – if you try to grab a DOM node that doesn’t properly exist, this code won’t work. Go check out the page at http://localhost:8000/view.html. The page should look empty (we aren’t importing any data yet), but reload the page multiple times while using the following development tools:

  • Use the DOM inspector tool to make sure you have properly created the container DOM nodes with the proper classes in the document body.
  • Use the Network tool to ensure you’re loading bootstrap.css, styles.css, jquery.js, and controller.js with HTTP status codes of 200. Look at the jQuery and Bootstrap files to make sure you’re importing the code you think you are.
  • Look at the JavaScript console to see if there are any errors.

Once it looks right or close enough to it, commit:

git add `view.html`
git commit -m "Initial report view template - DOM structure and imports created."

Business logic: controller.js

Now it’s time to tie all of this work together with JavaScript and jQuery. In controller.js:

// Use the "report" URL query parameters to determine which
// JSON file needs to be loaded.
// For example: localhost:8000/report.html?report=transportation
// means to get the report data from "transportation.json"
//
// If there is no query parameter present, the reportName
// variable defaults to "communication.json".
const parameters = document.location.search;
const reportName = parameters.split("=")[1] || "communication";
const reportPath = "data/" + reportName + ".json";

// Fetch data, then feed data into callback function
$.getJSON(reportPath, createReport);

//
// Supporting code
//

// master callback
function createReport(json) {
  createTitle(json.meta);
  createMain(json.data);
}

// create Title section
function createTitle(metadata) {
  $('.Meta__Government').html(metadata.municipal_body);
  $('.Meta__Title').html(metadata.title);
}

// create data section of report
function createMain(rows) {
  for (let i = 0; i < rows.length; i++) {
    const $reportRow = createRow(rows[i]);
    $('.Report').append($reportRow);
  }
}

// create individual items on report
function createRow(data) {
  const $reportRow = $("<div class='Report__Row row'></div>");
  const $label = $("<div class='Report__Label col-6'>" + data.label + ": </div>");
  const $value = $("<div class='Report__Value col-6'><span>" + data.value + "<span></div>");

  $reportRow.append($label, $value);

  return $reportRow;
}

Test, Iterate, Deploy

Test this at the following URLs:

  • http://localhost:8000/view.html
  • http://localhost:8000/view.html?report=transportation

Once it looks good, save it:

git add controller.js
git commit -m "Added business logic to extract the correct data and display it in the DOM."
git push origin master

Now deploy it:

git checkout -b gh-pages
git push origin gh-pages

And ping the Team Lead with that live URL!

Recap

In this chapter, you used jQuery and a sophisticated data and file structure to create a report generator.

exercises

  1. Read about jQuery objects in the documentation.

See: https://learn.jquery.com/using-jquery-core/jquery-object/

x. Turn this tutorial into a GitHub repo you name jquery-demo.

https://learn.jquery.com/about-jquery/how-jquery-works/

x. Review the jQuery document

https://api.jquery.com/category/attributes/

x. https://api.jquery.com/category/css/

x. HTML5 data attributes

x.Note that libraries are not frameworks. Libraries are about picking and choosing functionality you want, whereas frameworks seek to control how you structure much larger parts of your codebase. We will cover frameworks when we talk about single-page applications.

  • Reading library source code is a great way to learn!