JavaScript and jQuery

JavaScript (and jQuery) are important in CS304 primarily because of its importance in Ajax, which is a different way for the front-end (a web browser) to interact with the back-end (web server, including middleware and databases). However, we will defer Ajax until next time, because we first need to learn JavaScript and jQuery well enough to make effective use of Ajax.

In short, our destination is Ajax. To get there, we need to know some JavaScript (JS) and jQuery (JQ).

Plan

Our plan to get to Ajax is to quickly review the JavaScript language, but only the parts we need. We'll take a brief look at the DOM, or Document Object Model and event-handling. Then, we will have an even quicker, more cursory look at jQuery, because jQuery makes the Ajax request and response much easier than it is in raw JS1. jQuery also makes searching and modifying the DOM easier, so it's not quite out of a job yet.

We will then take a brief detour to learn what a callback is, which is incredibly important in modern, event-driven programming2. This will prepare us to learn Ajax.

Readings. There are several topics in this collection of readings:

  • JavaScript itself. If you don't know JavaScript, put it near the top of your to-do list, particularly for web development. Google for more tutorials and introductions if you find it insufficient.
  • Document Object Model (DOM). The DOM is introduced in this page, with links to additional readings if you'd like more information.
  • jQuery (JQ). This important JS library is introduced in this page, with links to API documentation for a few important methods.
  • Events. One of the critical things that JQ helps us do is to work with Browser Events. These are introduced in this page.

This webpage itself is 12 printed pages long, so a total of about 21 pages.

JavaScript

JavaScript is a dynamic language that is widely supported by modern web browsers. It is similar syntactically to Java, but semantically to Lisp and Python.

JavaScript is the most important language for web development. It's used in the front-end (the browser) and also in the back end (the server), using node.js. Later in the course, I'll explain the features that make it so important in the back end. For now, I'll explain that it's the only way to do programming in the front end, which users increasingly want and expect.

To program the front end, you need to know JavaScript, the DOM (the Document Object Model) and Events. jQuery is a library that makes modifying the DOM and working with events easier.

If you don't know JavaScript, you should consult these references:

In the following sections, I'll review a few essentials which will help those of you who just need some reminding, but this is not complete, and you should definitely avail yourself of some of the resources above if you don't know JavaScript.

The SCRIPT tag

You switch from HTML to JavaScript (JS) using the script tag. If you use the src attribute, you can load JS code, including the jQuery library, from another file or URL, but then the body of the script element is ignored.3

Basic Syntax

JS uses syntax like C and Java, so both // comment and /* multi-line comment */ work as comments. Statements look like Java, ending in semi-colons. (JS has a mis-feature that allows semi-colons to be optional by allowing the parser to guess where they should be; don't use this mis-feature, because an incorrect guess is hard to debug.)

/* omit this dumb code 
  var x = 3;  // magic number is 3 
  var y = 7;  // another mystical number 
*/ 

Major control structures (if statements and for and while loops) look just like C and Java:

// nested loops to find and display prime numbers.
    var i, j; 
    for( i=2; i < max; i++ ) { 
        // console.log('prime candidate is ',i)
        // loop over possible factors 
        j = 2; 
        isPrime = true;
        while( j*j <= i ) { 
            // console.log('trying possible divisor ', j)
            if( j*Math.floor(i / j) == i ) { 
                // j divides i, so i is not prime
                isPrime = false;
                break; 
            }
            j++;
        }
        if(isPrime) {
            console.log("prime: "+i);
        }
    }

Useful tools for debugging are built-in functions alert (which halts the program and pops up a window that must be acknowledged) and console.log which writes its argument to the console, which is part of the developer tools in every browser. Google for browser javascript console for your browser, if you can't find it. There's also debugger; which will throw you into the debugger at that line.

Datatypes

JavaScript has a few scalar datatypes:

  • strings (delimited by either single or double quotes)
  • numbers, notated in the usual way
  • booleans, notated by the bare words true and false. Unlike Python, these are lower case.

Like Java, the string concatenation operator is + (the plus sign). Unlike Java, the + operator can be either add (if both operands are numbers) or string concatenation (if either operand is a string), and this isn't known until run-time, since JavaScript is dynamically typed. This is an ugly facet of the language, causing innumerable mistakes, so be careful.

Dates

JavaScript has a reasonably nice and convenient Date object. The Date function returns an object that captures the current date and time and has methods to return those values:

var d = new Date(); 
console.log("Today is "+d.getMonth()+"/"+d.getDate()); 
console.log("now is "+d.getHours()+":"+d.getMinutes()); 

JavaScript has two beautiful compound datatypes, arrays and objects. Both have a simple and convenient literal syntax.

Arrays

Arrays look just like lists in Python:

// an array of some primes 
var primes = [2, 3, 5, 7, 11, 13 ]; 
console.log("we currently have "+primes.length+ " primes."); 
primes[6] = 17;  // add another 
primes.push(19);  // and another 

As you would expect, arrays are zero-based and indexed by integers. They support a number of useful array methods as well.

Objects

In JavaScript, an object is a data structure of name-value pairs, what other languages call hashtables (Lisp, Java), associative arrays (PHP), dictionaries (Smalltalk, Python), hashes (Perl), and so forth. (In a later lecture, we'll learn why they are called objects.) Here's an example:

// an object representing a movie 
var movie1 = { title: "Dr. Zhivago", 
               director: "David Lean", 
               starring: ["Omar Sharif", 
                          "Julie Christie", 
                          "Geraldine Chaplin"], 
               release: 1965 } 
movie1.running_time = 197; // minutes 
console.log("The title is "+movie1.title); 

Note that values can be scalars or compound; here we have an array literal of strings for the stars.

JSON

This object literal syntax is so compact and useful that it is now one of the more common representations of data on the web, called JSON or JavaScript Object Notation. JSON objects are commonly sent to and received from servers as the data of an Ajax call.

You can convert a JavaScript data structure of strings, numbers, booleans, arrays and objects into a string (suitable for sending or receiving over the web) using the method JSON.stringify. You can convert such a string back into the data structure using the method JSON.parse.

var movie_string = JSON.stringify(movie1); 
var movie_copy = JSON.parse(movie_string); 
if( movie1.title != movie_copy.title ) { 
    alert("This shouldn't happen."); 
} 

An important note on terminology: this concept of turning a data structure into a string, suitable for writing to a file or transmitting across a network, and then reversing the operation to re-create the data structure is a common one in computer science, not reserved just for JavaScript. One standard term for it is Serialization.

Variables and Scope

In JS, variables don't have types; data does. This is like Python and different from Java. So a variable can store any type of data, and you don't have to declare the datatype. The following is fine:

var x = "five"; // a string 
x = 5;  // a number 
x = true; // a boolean 
x = [2,3]; // an array 
x = {x: 2, y: 3};  // an object 

When creating a variable, you can declare it using var. For global variables, the var is optional, but you should do it anyhow.

Functions

Functions in JS have a very nice literal syntax. The following creates a function named add5 and invokes it on 2:

  function add5(x) { 
      return x+5; 
  } 

console.log("the result is "+add5(2));

You can also have an anonymous function. The following creates an anonymous function that adds four to its argument. The anonymous function is stored in a variable called add4. The last line invokes the function on 3:

var add4 = function (x) { return x+4; }; 

console.log("the result is "+add4(3));

Functions and variables share the same namespace, so the preceding two ways to create a function are (nearly) the same. (The only difference is in minor ways such as error messages, where an error in a named function can say what the name of the function was.)

In the example above, is add5 a function or a variable? It's both: add5 is variable whose value is a function named add5. What about add4? Is add4 a function or a variable? It's both, because it's a variable that contains an anonymous function, but since the variable name can be used anywhere that a function name is used, including in invoking the function, add4 is a function.

Anonymous functions are used a lot by JavaScript programmers, so it's a good idea to get comfortable with seeing them.

A variable is essentially either global (declared and used outside any function) or local (declared inside a function). The distinction is the critical use of the var keyword.

var X = 5;  // global named capital X 

function addX(y) { 
    X++;         // increments global X 
    return y+X;  // refers to global X 
} 

function addX2(y) { 
    var X = 3;   // new local named capital X 
    X++;         // increments local X 
    return y+X;  // refers to local X 
} 

(There are other scopes, such as closures, but we won't make much use of them for now. Also, modern JavaScript now has the let keyword for local variables. It is similar to var. The differences are subtle and rarely important. I'll use var, but using let instead will almost always work.)

There's also const which is for values that never change:

const tau = 2*Math.pi;

DOM: the Document Object Model

One of the key things that you can do with JavaScript is to modify the contents of the browser: changing the structure of the document, including adding and removing content. You can also alter the style of the elements, dynamically changing the CSS classes of elements or directly altering the CSS rules.

Take a moment to think about that: we tend to think of a web page as a static thing that someone wrote, saved to an HTML file, and web server delivered to our browser. The DOM allows the web page to become a dynamic data structure, with things being added, removed, changing style, and so forth. This is pretty amazing. It's also very important in web development. Every time you click or tap a web application and it changes content or style (maybe something is hidden or revealed), the DOM is involved.

The API or Application Programming Interface by which JavaScript can modify the document is called the Document Object Model, or DOM for short.

The DOM entails a lot, but one thing to know is that your document is a tree of nodes. So, for example, this paragraph is a child of the BODY element, and the em tag earlier is child of this paragraph. In the next section is an aside with a gray background, containing a paragraph and an unordered list, UL.... And so on.

DOM References

Many of the following are excellent introductions to the DOM, but they use the native JavaScript API. The raw DOM is actually not that hard to use from JS, but the jQuery library makes it even easier, so rather than learn two ways to modify the DOM, we'll skip over this and modify the DOM via JQ.

The following is a list of useful but optional references, but you don't need to learn the raw JS API to the DOM, so feel free to ignore those parts.

Because jQuery makes manipulating the DOM easier, let's learn jQuery.

jQuery

jQuery is a JavaScript library of useful methods for manipulating the document, by which I mean things like this:

  • Adding structure. For example, the back-end sends some new Facebook content; JQ can add that to the page.
  • Removing structure. You finish composing a Gmail message in a little sub-window of your browser window and you click on send. JQ can remove the sub-window and put the focus back on your main Gmail window.
  • Modifying style. You type some stuff into a Google Doc, and moments later, the phrase "all changes saved" appears at the top of the window, then fades to gray and disappears over the course of several seconds. JQ not only inserts the text, but sets its color and animates its changing color and opacity.

It does a few other things as well, including Ajax. For example, those Facebook updates, sending the Gmail, and sending the document changes are all done via Ajax.

jQuery has a small footprint, which means it doesn't take a long time to download to your browser and doesn't take up too much memory once it is loaded. It's well-supported and extremely popular. Google, Facebook, and many other tech companies use and support it.

For extreme brevity, everything in the jQuery library is accessed by via one function whose name is $ — yes, the dollar sign character. A synonym of the $ variable/function is jQuery, but that's rarely used. After all, it may be clearer, but it's six times as much typing!

jQuery Usage

There's a pattern to most jQuery usage:

$(selector).method(arg); 

The selector argument uses CSS syntax to select some set of nodes or elements in your document to operate on. The method then operates on that set in some way. If the method needs to know additional info, that's supplied in the arguments.

Here are some examples:

// change the CSS of all paragraphs (P elements) to make the text blue: 
$("P").css("color","blue"); 

// change the CSS of all elements of class "important" to have red text: 
$(".important").css("color","red"); 

// change the CSS of the navbar to be red on white. Notice the use of an 
// object literal to package up two changes 
$(".important").css({"color":"red","background-color":"white"}); 

// add the class "important" to all H2 elements: 
$("h2").addClass("important"); 

// change the text of all H1 elements to "Cool Stuff" 
$("h1").text("Cool Stuff"); 

// change the HTML of the copyright notice to this year 
var d = new Date(); 
$("#copyright").html("&amp;copy; "+d.getFullYear()); 

// add bananas to the grocery list. 
$("ul#groceries").append("&lt;li&gt;bananas"); 

// delete all H3 elements from the document 
$("h3").remove(); 

// hide (make invisible via CSS display: none) all paragraphs in the sidebar 
$("#sidebar p").hide();

We could go on, but you get the idea.

jQuery API

The jQuery API is well documented. Here are some of the methods we used above:

You can learn a lot just by poking around in there and reading some of their examples and notes.

Method Chaining

The implementation of jQuery uses a clever trick that can create a great deal of efficiency and brevity. Supplying a selector to the jQuery function and invoking it returns a object that represents the set of matched elements. That object supports the methods like the ones we looked above. Furthermore, most of those methods return the same object as their return value, which means that we can keep operating on the same set, just by invoking another method, chaining them together.

That's all very abstract, so let's see some examples.

This first example is how a novice might do a series of things with some selected objects. In this example, I'm using sel as a stand-in for the selector string, which might be something like #foo or .bar or [data-role='trigger']. All that's important is that the selector matches some set of elements on the page.

$(sel).addClass('important');        // make them important 
$(sel).css('color','red');           // make them red 
$(sel).append("&lt;em&gt;really!!&lt;/em");   // add an exclamation 
$(sel).hide();                       // and hide them?? 

That works fine, but the trouble is that jQuery has to keep finding all the objects, so it wastes a lot of work.

A more experienced or efficiency-conscious person might do the following:

var elts = $(sel);                 // get a set of DOM objects 
elts.addClass('important');        // make them important 
elts.css('color','red');           // make them red 
elts.append("&lt;em&gt;really!!&lt;/em");   // add an exclamation 
elts.hide();                       // and hide them?? 

That's efficient, but a bit tedious to type. An experienced and terse jQuery coder might do the following:

$(sel).addClass('important').css('color','red').append("<em>really!!</em").hide(); 

Of course, that's really ugly and hard to read. The important point is that each method is just called on the return value of the one to its left. The layout of the code isn't important, so we are free to lay out the code nicely, maybe with comments. So, the true jQuery expert writes the following (notice the lack of semi-colons, which would interrupt the chain by ending the statement):

$(sel)                           // get a set of DOM objects 
   .addClass('important')        // make them important 
   .css('color','red')           // make them red 
   .append("&lt;em&gt;really!!&lt;/em")   // add an exclamation 
   .hide();                      // and hide them?? 

Note: One drawback of this technique of returning a set of matched elements is that the empty set is a perfect valid set, so jQuery is perfectly happy to do all those operations above on an empty set of elements, thereby doing nothing, and never give you a peep of complaint or warning. So if your jQuery isn't working and there's no error message, scrutinize your selector expressions. In fact, I often end up doing something like this when I'm debugging:

var x = $(sel); 
console.log("matched "+x.length+" elements"); 

If that shows that the number of matched elements is zero, operating on the set will be pointless.

In fact, this debugging technique is useful enough that I wrote a jQuery plug-in to do it for me very easily. See bounds plugin if you're interested.

Building Structure

Before we get to events and Ajax, we should take few minutes to look at operating on the structure of the document. We'll use jQuery to do this. We'll start with adding a list of prime numbers to the web page. First, we need to have a destination for them:

<div style="border: 2px solid maroon" id="prime-container">
<p>Our primes:</p>
<ul id="prime-list"></ul>
</div>

Notice that the list is empty. This seems odd, but it happens all the time with dynamic documents. The static document is empty, just providing structure for the content, and all the interesting stuff is added dynamically.

Now the code to add some primes to that list:

function addPrimes( primes ) { 
    primes.forEach(function (p) { 
        $('<li>')
            .text( p )
            .appendTo('#prime-list');
    }
} 

addPrimes( [2, 3, 5, 7, 11, 13, 17] );

Notice how we used an anonymous function and the forEach() method for an array, which invokes the function on each item in the array.

Here it is:

Our primes:

    You might wonder what the <li> does as the argument of the jQuery function, since it's not a CSS selector. What happens is that jQuery creates the given element, but it is not (yet) attached to the document. Here, we attach it to the document with the jQuery's appendTo method.

    An alternative way to do this is to build the entire list up and only attach it to the document at the end. This is more efficient, since the document only has to be re-rendered once for the list, as opposed to once for each element. But we won't usually worry about efficiency.

    Here's the destination container.

    <div id="prime-container2">
    <p>Another list of our primes:</p>
    </div>

    Here's our JavaScript code:

    function addPrimes2( primes ) { 
        let listElt = $('<ul>');
        primes.forEach(function (p) {
            $('<li>').text(p).appendTo(listElt);
            })
        $("#prime-container2").append(listElt);
    }
    addPrimes2( [2, 3, 5, 7, 11, 13, 17] );

    Here's the finished list:

    Another list of our primes:

    DOM Events

    In addition to letting us work with the DOM, jQuery lets us work with events. Events are important ways of hooking into user behavior: a user clicking on something or mousing over something is an event, and we can make things happen when that event occurs. The way that event-handling in the DOM works is that you can say:

    when event E occurs to DOM element D, please invoke function F

    Here's a partial list of some common DOM events:

    • click: when you click on something
    • dblclick: when you double-click something
    • mouseover: when your mouse is moved onto an element
    • keypress: when a key on the keyboard is pressed
    • load: when the document or an object like an image finishes loading
    • submit: when a form is submitted

    We'll mostly be working with .click().

    Let's make that more concrete. At the end of this section, I'll put an element whose ID is fred. Let's write some code that would turn that element a random color when we click on it. First, a useful but uninteresting function:

    function randColor() {
        var colors = ['red','orange','yellow','green',
                      'blue','purple', 'magenta',
                      'cyan','black','white'];
        var randIndex = Math.floor(Math.random()*colors.length);
        return colors[randIndex];
    }

    Now, the event-handling magic. This says to change the DOM element whose ID is fred to a random color whenever the code is executed.

    // jQuery magic to turn it a random color: 
    $("#fred").css('color',randColor());

    Okay, very nice, but that's not yet what we want. We'd like the user to be able to turn the header a random color just by clicking on it. So, one step on the way to do that is to package up that code into a function, say turnFredRandomColor:

    function turnFredRandomColor() { 
       // jQuery magic to turn it a random color: 
       $("#fred").css('color',randColor()); 
    } 

    Then, whenever we want to turn that element a random color, we just invoke the function:

    turnFredRandomColor(); 

    However, we want the user to be able to have that function invoked by clicking on the element. More precisely, we want to say that whenever the #fred element gets a click event, we'd like the turnFredRandomColor function invoked. jQuery provides a very easy way do to this, using the same pattern we've seen many times:

    $("#fred").click(turnFredRandomColor); 

    Like something out of Alice in Wonderland, here's a button that says "click me", so do that:

    Now, there are some very important points to make: we are not invoking the turnFredRandomColor function right now. Instead, we are giving it to the click method, much like we gave the 'color' string and the value of the randColor variable to the css method above. That is, the function is merely a piece of data that is being passed as an argument. It is not being invoked now.

    To invoke a function we give its name (or, equivalently, a variable whose value is the function) followed by parentheses containing any arguments to be passed. Since we are not invoking turnFredRandomColor now, it's not followed by parentheses.

    When does it get invoked? The browser will invoke it when the event happens. The function is an event handler.

    The function is also an example of a callback. A callback is a general Computer Science term for a function that is invoked later, when something happens or has happened. They're used in graphics programming, processing data, GUI programming and lots of other situations.

    By the way, an experienced jQuery programmer wouldn't bother to devise that cumbersome name (turnFredRandomColor) for a function that they are never going to refer to again after handing it to the click method. Instead, they use an anonymous function literal, putting all the important code right where they need it:

    $("#fred").click(function () { 
        var colors = ['red','orange','yellow','green','blue','purple']; 
        var randIndex = Math.floor(Math.random()*colors.length); 
        var randColor = colors[randIndex]; 
        // jQuery magic to turn it a random color: 
        $("#fred").css('color',randColor); }); 

    The whole function literal is the argument of the click method — notice the close paren on the last line, after the closing brace of the function literal.

    One of the events that will be important in using Ajax is the event of some data being loaded from a server. We're getting closer to our destination now.

    The this Keyword

    The function turnFredRandomColor lacked some flexibility. It always operated on the #fred element (that is, the DOM element whose ID is fred; I'll use the CSS language to abbreviate my descriptions and reinforce the language).

    A more flexible function would instead operate on this, which is a special dynamic keyword in the JS language. On every method call, the keyword this is bound to the object that the method is invoked on, much like the this variable in Java. We haven't learned OOP syntax in JavaScript, and we probably won't, but it doesn't take us much out of our way to mention this.

    In addition, the this keyword is bound to the DOM element that had the event happen to it. In other words:

    when event E occurs to DOM element D, please invoke function F and bind this to D

    How is that useful? Try clicking on the different list items in the following list:

    • apples
    • bananas
    • cider
    • daikon
    • eggplant
    • figs
    • grapes

    Here, I've changed the function to set both the text color and the background color. Most combinations will be unreadable, but you can always click again. The point is that list item acts independently.

    Here's the code:

        $("#groceries li").click(function (event) {
             $(this)
                  .css('color',randColor())
                  .css('backgroundColor',randColor());
        });

    Things to note:

    • The selector, "#groceries li" selects every LI that is a descendant of #groceries, so it selects 7 DOM elements here.
    • To each selected element, it adds the click handler (that anonymous function), so there are 7 elements that use this function as their click handler.
    • The function refers to this which will be the actual LI that you clicked on
    • The function wraps this in the jQuery function, so that it can use jQuery methods on the DOM element
    • The function chains together two methods to change both the foreground and background colors of the DOM element

    A complex result from a very compact notation!

    Delegated Event Handlers

    But wait, there's more. (If your brain full, I suggest coming back to this section later.) The grocery list example above is good, but as we mentioned, it creates seven identical event handlers, which isn't efficient. jQuery allows us to use event bubbling to attach the event handler to the single ancestor, and operate on the event target (which is bound to this). So modern best practice is to use a delegated event handler, delegating the work to a single static ancestor. Here's an example using a list of my favorite movies:

    1. Dr. Zhivago
    2. Lord of the Rings
    3. Schindler's List
    4. Black Panther

    Here's the code:

        $("#movie_list").on('click', 'li', function (event) {
             $(this)
                  .css('color',randColor())
                  .css('backgroundColor',randColor());
        });

    We'll learn more about event bubbling and delegated handlers next time; this is a preview.

    Video

    In class, we'll do some exercises and see some examples that will show how JavaScript and jQuery allow us to modify a page. I created a video of them. Viewing that before class will be really helpful. Please look in the videos page to see that video. It's about 12 and a half minutes long.


    1. This statement is out of date, because the latest versions of JavaScript include a fetch function that replaces jQuery's support for Ajax. Still, if you understand one, you can learn the other in 10 minutes. 

    2. This statement is also out of date, now that JavaScript supports promises, which are an improvement over callbacks, though many of the same concepts necessarily apply. Learning promises, however, is not 10 minutes. I plan to teach it outside CS 304 sometime. CS 304 is already full. 

    3. I'm not teaching modules, another new feature of JavaScript. We won't need it in this course, but you should put learning it on your to-do list. It's on mine.