Modern web pages change and react based on user actions or changing data. Sometimes, these changes are done on the server: a new set of HTML for displaying the desired data is constructed on the server right before it is sent across to the client. Sometimes, these changes are done on the client side: changes to the HTML or style are handled by the client’s browser. These are sometimes called back-end and front-end approaches to making websites responsive.
Many modern web sites contain both front-end and back-end components. For example, data about user purchases might be stored centrally on a server, and accessing that data will require some work on the back end. But since network communication can be slow, user-interface elements can be made most responsive through Javascript on the front end. Furthermore, although computation can often be performed either on the client or server, the owner of the website must pay for computation on the server; if that computation can be done on the clients own computer, then the web application will scale more cheaply.
This page discusses how to use Javascript to actively manipulate HTML elements, and to respond to user input or actions.
Information about HTML elements is stored in something called an object. An object contains several variables; the variables can be accessed using dot-notation. Some of those variables might be references to functions; we call such functions methods. Methods have access to the data in an object (stored in the other variables), and can compute values using those values or change the values.
Here are some examples of methods of string objects that compute values based on the information in the string:
It can be useful to split strings into pieces. The split()
method of the string class takes a single parameter, which is the a string describing the character that separates elements of the string. For example, the string of stock prices "127.3,123.2,129.3"
can be split into strings containing numbers using split with a parameter of “,”. A string can be split into an array of letters by splitting on an empty string ""
.
If you’d later like to make an array of strings into a single string, you can use the .join
method of arrays. join
takes a single parameter, the string to put in between each of the elements of the array as the string is formed.
Strings are a special type of object, and some special rules apply. The data in a string cannot be changed; you can view, but not change, the value at string position 0, for example. For this reason, there are no string methods that change the string they operate on.
However, we can create a new string from the old, and make use of the new string. Write a single line of code that reverses the string “!REDRUM” and prints the result. You may find the reverse
method of arrays to be useful. It takes no parameters.
You might have heard of the concept of object-oriented programming. Objects are a way of packaging related data together neatly. An object can be thought of as a record in a database. For example, you might have an index card for someone named “theDonald” and another for “hillary”. Each card would have vital statistics associated with each candidate:
An empty object with no properties can be created using empty braces {}
. Properties can then be added to the object using dot-notation: theDonald.party = "Republican"
. You can think of the property party
as being a variable that is contained within the object theDonald
; the dot says to go inside the object and fetch (or create) the variable party
.
So party
is a property of Trump, and it has a particular value associated with it, Republican
. Objects typically have several properties. In our example, each of the two objects has the properties party
, hairColor
, and age
.
Debugging note: you can use the JSON.stringify
function to convert an object to its string representation for printing out. JSON string representations are also used to send information about objects across networks, or to save representations of objects to files.
Arrays and strings are themselves special types of objects. That’s why you can use the .length
property to find out how many items an array or strings holds.
An object can be thought of as containing variables, which we call properties. Those variables may store numbers, strings, references to other objects, or functions.
It is useful if an object that represents or models a particular type of data contains references to functions that can act on that data. For example, imagine if you had an object meant to represent a ball. That ball object might have properties x
, y
, vx
, and vy
to represent the location and velocity of the ball. You might also have a function, draw, that draws ball objects, and a reference to this function might be within the ball object itself:
When an object has a property that contains a reference to a function, that function it is called a method.
Why do we need methods? Imagine that you have very many different types of object that you would like to draw. Maybe you have a function that draws a ball, another function that draws a tree, and a third function that draws the entire user interface for the cloud9 web application. If we associate each of these methods with an object, then this helps us keep the methods organized, so that we can quickly find them in the code, and name them in a way that makes sense.
An array represents an ordered list; you can store an item at say, location 5 in the list, and later ask the question, “What item is at location 5?” We say that there is a correspondence between 5
and that item, and we say that the item is indexed by the number 5.
Sometimes it is useful to index items using a string, rather than a number. For example:
We say that a dictionary creates an association between each key and its associated value. You can think of a key as being like a word in the Oxford dictionary: intrepid
. You can think of the value as being like the definition: Fearless or adventurous
. The key is the thing you know; you use the key to look up the value.
We can create a dictionary using curly braces: var myDictionary = {};
. When the dictionary is created, we can seed it with some initial pairs of keys and values, as in the example above. The key of each pair appears before the colon; the value appears after the colon.
Once the dictionary has been created, we can retrieve or change the value associated with a particular key by using the key inside square brackets, just as if the key were an array index.
The key for a dictionary might be a string, or a number, or something else. For now, we’ll mostly use strings.
Objective: use a dictionary to express the relationship between key and value pairs.
The wavelength of blue light is about 450 nanometers. The wavelength of orange light is about 600. Green is 530 and yellow is 580. Using strings representing the names of colors (e.g. “blue”) as keys, create a dictionary that stores the appropriate wavelength of each color light as the value for the proper key.
Here is a solution.
Dictionaries can store anything as values. Let’s say that Cathy is friends with Alice and Elmer, and various other people have various other friends. We could use a dictionary to represent the network of which people have which friends:
We could use such a data structure to answer many different questions. How many degrees of separation are there between Cathy and John, and how many introductions would need to be made for them to meet (route length)? Who has the most friends? If I would like to influence the network, who is the best person to know?
Dictionaries have many uses. Here’s another. Let’s say that I would like to find documents on wikipedia related to surgery. Some of those documents might not even use the word surgery, but by reading them, a human would be able to tell the rough area of the content. How can a computer compute document similarity?
One idea is that words used frequently in a document tell you something about that document. A document that uses the word “scalpel” many times might be similar to another document that also uses the word frequently.
We can use a dictionary to efficiently count how many times each word appears.
In Javascript, objects and dictionaries are really the same thing; technically, we say that the concept of objects is implemented using dictionaries.
One implication of this that you can use something called dot-notation to access the values associated with keys, as long as the keys are strings.
To access a value using bracket notation, follow the name of the object with square brackets surrounding the key; if the string is a key, it will be surrounded by quotes. To access a value using dot notation, follow the name of the object with a dot, followed by the name of the key without the quotes.
If you are particularly intrepid, you might ask why there are two notations for the same thing. It depends on context. If the structure holding the keys and values is intended simply as a look-up table, we’d probably call it a dictionary. So in the example with birthdays, we’d probably call birthday
a dictionary and use bracket notation. It’s just a table of birthdays.
If the structure is intended to act more like a record in a database, grouping properties of some physical or virtual object, we’d probably call it an object, and use the dot notation. theDonald
is a record of information about the properties of some real (?) object.
You can embed Javascript code into an HTML document using the <script>
tag pair. For example, if you wanted to call the Javascript alert()
function every time a web page was rendered, you could do that:
HTML code uses tag pairs to label components of a document. Some components may contain other components; the body of the html may contain a list, which contains list items, which themselves might contain both text and links, for example.
Think about the structure of an HTML document. The outmost tag pair which contains everything else is probably the <html> </html>
pair. First, that tag pair contains both a head
and a body
section. The head section contains a title, which the body might contain lists of list items, etc.
We can visualize the document as a tree. Here’s an example from dabrook.org:
We say that the root of the tree is the HTML element. That HTML element contains the head and body, so they are drawn as branches from the root. (Computer scientists frequently draw trees upside down, with the root at the top. It’s just easier.) The body contains two div
’s, which themselves contain various content.
How can we manipulate an HTML document using Javascript? Javascript objects can be used to store both data and references to certain special functions called methods. The mechanism the browser provides to fetch and work with HTML elements is called the Document Object Model, or DOM, because objects are used to refer to elements. There are two stages:
In the code above, document.getElementById("second_image")
fetches a reference to an object that can be used to manipulate the img
element with an id
of "second_image"
. Since no two objects share the same id in well written HTML, document.getElementById
will always give access to just a single object to work with.
Once we have the object, we just set the width
attribute of the object to 50, and the browser notices the change and updates how the page is displayed.
You can insert some arbitrary HTML code into a document. First, you need an element with an id in the document, and no text between the tags, to serve as a marker. Grab that element using document.getElementByID
, and then use the special attribute innerHTML
to set the HTML text that appears between the tags.
A span
or a div
is a pretty good choice for a marker element, since spans and divs aren’t really intended to do anything but label or partition the document:
Here’s a simple web page:
Write some javascript that creates a table within the div with id “ticker_table”, using the data in the variables in the javascript code provided.
If you have a textarea
element in your HTML, you probably need to get the text that the user typed in, and do something with it. You can use the attribute .value
to get the text as a string. Sometimes, you’d like to change the text in a textarea
. You can change the .value
attribute of textarea objects to change the text in the box. Here’s an example that does both:
Javascript runs our code, and that code has to run quickly and terminate, because while our code is running, the browser is unresponsive. That’s why infinite while or for loops are problematic in Javascript.
What if we want to write some code to be executed later on? For example, what if we wanted to write a clock that printed out the number of seconds that elapsed, once each second? So far, that should seem impossible, since our program runs once, and is long terminated one second from now, or two seconds from now, or a thousand.
So far, we’ve defined functions and then run them immediately. But Javascript lets us define a function, and then specify that this function should be run later, under some specific circumstances.
The provided Javascript function setTimeout
takes two parameters: a reference to a function to be run later, and the number of milliseconds to wait before running that function:
The function surprise
has been set as callback function: we specified that Javascript should call it later, under some specific circumstances.
This is a much different programming paradigm than we have seen so far. So far, you wrote a program, Javascript executed it, with the program counter marching merrily through the code one line after another. That still happens the first time your code is run, but with the ability to register callback functions for later use, the later executions are a bit trickier to predict.
If you write a website with buttons for a customer to click, you want some code to be run when they click a button: a callback. If you want to write a fancy animation, that animation will have to draw something new every few milliseconds: a callback. If you want to update stock prices live and show them on your website, you need to write a callback to fetch stock prices from some other site every few seconds. If you want to show current weather, you’ll need to write code that checks the weather every hour. Callbacks are important.
It’s important to understand that callbacks are not magic: there is still just one single program counter (this is only mostly true), and callbacks are processed in the order they are triggered. So callback functions, like your original Javascript code, have to do their work quickly and terminate. No infinite loops inside your callback functions!
Let’s see how we could write a clock program that counts from 10 down to 1 and prints “blastoff”. You might think there would be a loop, but there won’t be. Instead, we’ll write a function that is called every one second, and updates a counter variable, prints something on the screen, and registers the next call.
We call the construction in which the countdown
function calls and registers itself as a callback a chained callback
, and it is quite a good way to get something that behaves like an infinite loop in Javascript, without taking over all processing power or hogging the program counter.
Notice that if you run the code a second time before the countdown has terminated, the countdown gets jumbled, since each program is interleaving chained callbacks.
The examples so far are not very dynamic; the Javascript code runs, and changes something, but that all happens before the user even has a chance to see it. What if we wanted to make a page with content that really changes over time?
There is a function setInterval
that instructs the browser to call a function repeatedly every so often. setInterval
takes two parameters: the name of the function to call (without parentheses), and the number of milliseconds to wait before each call.
In the next example, setInterval
instructs the browser to call the updateTime
function every 1000 milliseconds.
We call updateTime
in the last example a callback function because setInterval
instructs Javascript to call it (back) every time a certain event occurs. In this case, the event is that 1000 milliseconds have elapsed. You can give any name you like to your callback functions; you just need to tell Javascript what they are and when they should be called by calling functions like setInterval
.
By combining HTML and Javascript, you can set up an entire user interface for a fairly complicated program, all right in the browser: a web application. For example, c9.io provides a full-featured editor for code; the interface is constructed using HTML, Javascript, and CSS. Social networking sites like Facebook piece together hundreds of interface components into a larger whole. Google Docs builds traditional desktop spreadsheet and word processing into a browser. Even the small code examples on this page are constructed automatically by Javascript code that searches through the document for certain div elements, inserts some special HTML code at those locations, and loads in sample code from a file.
To build a web application, we need some ways to respond to user input. We can attach callback functions to user input events. The simplest example is a button
element in HTML, with a callback bound to the onclick
event.
Notice that rather than simply using name of the function to register the callback, as with setInterval
, the value of the onclick
attribute of the button is a string containing some Javascript code to run; that string just happens to contain a function call. Conceptually, the clicked
function is still being used as a callback.
You might wonder why we created a clicked
function at all in the last example. We could have just put code to call alert
into the onclick attribute directly, but the code would have been harder to read.
Build a website with three sections of content, each in its own div
. Add one button corresponding to each div, so that when the corresponding button is clicked, that div appears, and the other two divs disappear. (The css style “display:block;” makes a div visible, and “display:none;” makes it invisible.)
One of the less exciting but still critically important uses for Javascript on a web page is in form validation. If you create a textarea for the user to enter their name, with the intent of saving their name on your server, what happens if the user downloads a copy of Tom Sawyer from the internet, and pastes that text into your tiny text area? If you are not careful, Tom Sawyer will be sent over the network, costing you network connection quality, slowing your server down, and possibly overwriting your database or filling your storage.
So how do you prevent your competitors or enemies from using a nice textarea to smash data over your networks and into your server, and crash your system: a denial of service attack? Javascript is not really the answer, actually – it turns out that it’s not hard for someone to corrupt your Javascript code. However, it’s a starting point. Javascript can check the input in the text area to make sure it satisfies certain rules (is short enough, or of the expected type or value) before sending it over the network. If the data is bad, it will never make it to your server.
We won’t show an example; these days, most people use one of the many existing wonderful Javascript libraries for form validation. But what all of these libraries do is watch as the user types data into a textarea or other element, and use Javascript callbacks to validate the input before allowing it to be sent to a server.
If you need security (you do), you’ll also need to validate form data after it arrives at the server. The code you write on the server is protected, and more difficult for an adversary to modify. We’ll see in the next few lectures how to write server-side code.
You can’t code in Javascript for long before you hear about the jQuery library. Earlier versions of Javascript were not well standardized, and implemented slightly differently across browsers. The parts of Javascript that worked with the DOM were particularly flaky and non-uniform, and that was too bad, because manipulating web pages was sort of the point.
jQuery was a library that provided a single set of functions to manipulate the DOM that could be called by the web page coder. Those functions detected differences between browswers worked around the differences, so that the coder didn’t have to think about them; a beautiful example of an abstraction layer. jQuery also provided several nice utility functions that simplified common tasks. And it was good, and the people used it.
More recently, some have started to advocate not using jQuery. Any library, no matter how nice, adds size to your application, which costs network transfer speed and bandwidth: money. And jQuery was a victim of its own success; based on what was seen in jQuery and elsewhere, modern browsers have started to integrate many of the nice utility functions, and the integration between Javascript and browsers has started to standardize.
The debate continues: write lean, slim code that is self-sufficient and lean, but only runs on newer browsers, or support legacy browsers using libraries like jQuery? (Older versions of Internet Explorer still maintain significant market share in some markets, and are known to be particularly difficult to deal with.)
There are many libraries to choose from to provide extra features or to simplify coding. Some of those libraries, like jQuery, are purely Javascript and can be included by simply running a simple script tag and possibly putting a copy of the libray in the same directory as your html.
Other libraries are intended to interface with services provided by a third party, such as Google Maps or Yelp. Some portion of the work is done by a remote server, where data such as maps or reviews might be stored, and there’s a Javascript or other library that lets you interact with that server in some particular way. We can the library of functions and methods used to do that interaction between your code and the remote application the interface. Specifically, an Application Programming Interface, or API for short.
Google’s servers won’t talk to just anyone. I registered as a user of Google Maps APIs, and they gave me a code snippet that contains a special key that identifies who is connecting to the server. Here an example web page with that snippet for your to run:
Other APIs can be used to do things like track who has visited your site from where, so that you can collect customer data. You can register for Google analytics and copy the code snippet into your web page, and then use the Google Analytics website to analyze who has visited you. (You cannot tell exactly who has visited, but you might be able to tell where they are located, how long they were on the site, and which pages or products they spent the most time looking at.)
There are APIs to look at recommendations on Yelp, check the weather, and do a million other things.