Client-Side Processing

Peter Wood

Overview

  • JavaScript, HTML events and the Document Object Model (DOM) (slides 2-22)
  • HTML forms and Javascript functions (slides 23-26)
  • Navigating and manipulating the DOM (slides 27-37)
  • jQuery library (slides 38-41)
  • Retrieving XML using jQuery (slides 42-46)
  • Retrieving JSON using jQuery (slides 47-53)

Client-side processing

  • client program (e.g. web browser) can be used to
    • customise interaction with the user
    • validate user input (although HTML5 now provides this)
    • generate (part of) document dynamically
    • send requests to a server in the background
    • make interaction with a web page similar to that of a desktop application
  • this is typically done using JavaScript, since a JavaScript interpreter is built into browsers

JavaScript

  • interpreted, scripting language for the web
    • built in to browsers
    • also used for web servers, e.g. using Node.js
  • loosely typed
    • variables do not have to be declared
    • the same variable can store values of different types at different times
  • ECMAScript, 11th edition (June 2020) is the latest standard

Referencing a script

  • HTML <script> element specifies script to be executed
    • type attribute has value text/javascript
    • src attribute specifies URI of external script
  • usually <script> appears
    • in the <head> or
    • at the end of the document
    and just declares functions to be called later

Script execution

  • Javascript scripts can be executed upon, e.g.,
    • a script element being encountered in a document (not recommended)
    • event occurrences
  • many different events; some examples are:
    • window events: load, unload
    • mouse events: click, mouseup, mousemove
    • keyboard events: keydown, keyup
    • form events: submit
    • media events: play

Document Object Model (DOM)

  • previously W3C, now a WHATWG specification
  • defines API for HTML and XML documents
  • defines logical structure (model) of documents
  • document modelled as a tree (or forest) of nodes
  • using DOM, programmers can
    • build documents
    • navigate their structure
    • add, modify, delete elements and content
  • purpose is to provide portability across web browsers

DOM example

  • The following
    was generated by placing the following script
    <script type="text/javascript">
      document.write("<em>Document title</em>: ", 
                     document.title);
    </script>
    
    inside an HTML table cell (not recommended)

Document methods and properties

  document.write("<em>Document title</em>: ", 
                 document.title);
  • document is a special object referring to the document displayed in the browser window
  • write is a method defined on an HTML document, which writes text into it
  • title is a property defined on document, which retrieves the title

Events

  • more commonly, scripts are executed in response to events, e.g, clicking a button
  • the following button was produced using (old style):
    <button onClick="window.alert('Hello World!')">
      Click to see a message
    </button>
    
  • the button element creates a button
  • what is displayed on the button is specified by the contents of the button element

Event explanation

<button onClick="window.alert('Hello World!')">
  • onClick is an event attribute
  • window is a DOM object representing the browser window
  • alert is a method of window, which opens a new window displaying the message given as argument
  • here the script is embedded in the value of the onClick attribute
  • best practice dictates that HTML and Javascript should be separated

Calling a function

  • say we want to call a function when a button is clicked
  • we can use the following code (still old style):
    <button onclick="tableOfSquares()">Click to produce 
    table of squares</button>
    
  • this will produce the button which calls the user-defined function tableOfSquares
  • we need somewhere on the page to write the table
  • we use an empty div element with id="tos" on the next slide

Function output

Table of squares function

  • the following function produces a table of squares of the first n integers, where n is entered by the user:
    function tableOfSquares() {
      // Display a prompt with a zero in it
      const num = window.prompt("Enter an integer", "0");
      let myTable = "<table class='border'>";
      let count = 0;
      while(count < num) {
        // Each row contains an integer and its square
        myTable = myTable + "<tr><td>" + count + "</td><td>"
                           + count*count + "</td></tr>";
        count++;
      }
      document.getElementById("tos").innerHTML = myTable + 
                                                 "</table>";
    }
    

Comments on previous script

  • a comment is indicated by // (to end of line)
  • const declares a constant
  • let declares a variable (creates a binding)
  • variables do not need to be declared before use, nor are they statically typed
  • a variable can be initialised with a value, e.g., count is set to zero
  • prompt is a method of window, which opens a dialog box with the given message and default value for the input; it returns the value entered by the user

More comments

  • myTable is used to store a string representing an HTML table
  • JavaScript has the usual while and for loops
  • + is used for string concatenation
  • count++ adds one to the value of the variable count
  • getElementById is a document method returning a reference to the identified element
  • innerHTML is a property of DOM nodes which can be set by assigning to it a string representing HTML

Functions in JavaScript

  • the previous function was defined using a function declaration:
    function tableOfSquares() { ... }
    
  • it can also be defined using a binding:
    const tableOfSquares = function () { ... }
    
  • or using an arrow:
    const tableOfSquares = () => { ... }
    
  • note that this function has no parameters

Defining a function

  • function tableOfSquares has to be defined somewhere, either
    • in a script element in the document, or
    • in an external file with the extension js
  • in our case, all functions are defined in the external file client.js
  • this file is referenced in the head of this document as follows:
    <script type="text/javascript" src="client.js" />
    

JavaScript console

  • web browsers provide a way of running and debugging JavaScript code
  • in Firefox, this is found using the Web Developer → Web Console menu item
  • output to the console is done as follows:
    console.log(document.title);
    
    which produces
    Client-Side Processing
    ← undefined
    
    because console.log does not return a value; the output is a side-effect

Event handlers

  • the value of an onclick attribute is an event handler
  • rather than embedding the event handler code in the HTML, it is preferable to
    • bind the click event to the button, and
    • associate a handler function with the event
    in Javascript code separate from the HTML

Event handlers example

  • now the code for the button (which we need to be able to identify) is:
    <button id="hello-button">Click to produce message</button>
    
  • the code for binding the click event to the button and associating an event handler function is:
    document.getElementById("hello-button").onclick=helloAgain;
    
  • note that helloAgain is simply the name of the function to be called

Delayed binding

  • one possible problem is that the element with id hello-button is only available after the page has loaded
  • if the script is in the head, we need to delay binding the click event to the button, as follows:
    window.onload = function() {
          document.getElementById("hello-button").onclick = helloAgain; 
                    }
    
  • this binds the load event to the window object
  • it also associates an anonymous function with the event

Delayed binding example

  • when button is clicked, the event handler calls the user-defined function helloAgain
  • function helloAgain is defined as follows
    function helloAgain() {
      window.alert("Hello again world!");
    }
    
    in the file client.js
  • an alternative to using window.onload would be to use the defer attribute of the script element

HTML form fields

  • the above was generated by the following:
    <form>
      <label>Enter a word:</label>
      <input type="text" id="myWord" />
      <input type="button" id="myButton" value="Translate" />
      <input type="text" id="myResult" />
    </form>
    
  • the form element indicates an HTML form
  • the input element (with type="text") creates a single-line textbox
  • the input element (with type="button") creates a button with the given value displayed

Functions and form fields

  • an HTML form is usually used for submitting information to a server, but not here
  • in the JavaScript file (client.js)
      document.getElementById("myButton").onclick = myTranslate;
    
    will call myTranslate (next slide) when the button is clicked

Defining function myTranslate

  • function myTranslate is defined as follows:
    function myTranslate() {
       const word = document.getElementById("myWord").value;
       let result = "unknown";
       if (word === "hello")
          result = "buongiorno";
       else if (word === "goodbye")
          result = "arrivederci";
       document.getElementById("myResult").value = result;
    }
    
  • word contains the word the user entered
  • value refers to the contents of the identified input elements

Equality in JavaScript

  • JavaScript has two equality operators: == and ===
  • == tests if two values are equal (possibly after type coercion)
  • === tests if both the types and values are equal, so is considered safer
  • e.g., (1 == true) is true, while (1 === true) is false

Navigating the DOM tree

  • each DOM node object has a number of properties for navigation, e.g.:
    • firstChild
    • nextSibling
    • parentNode
    • childNodes
    which return, respectively, the first child, next sibling, parent and all children of the node

Other DOM node properties

  • other properties include
    • nodeName (return the name of an element node)
    • nodeValue (return the textual content of a text node)
  • often easier to navigate using the getElementsByTagName method:
    • takes an element name as argument
    • returns a collection of all element nodes with that name

Finding elements by name

  • say we want to output the value of each option element in the current document
  • we want them to appear as a list below when the following button is clicked:

Finding elements (function body)

  • we can use the following script:
    const options = document.getElementsByTagName("option");
    let output = "<ul>";
    for ( i = 0; i < options.length; i++ )
        output = output + "<li>" + 
                 options[i].firstChild.nodeValue + "</li>";
    document.getElementById("optionList").innerHTML = output + 
                                                      "</ul>";
    
  • getElementsByTagName returns a collection of nodes
  • length is a property of a collection; it returns the number of items in the collection

Function body (continued)

for ( i = 0; i < options.length; i++ )
    output = output + "<li>" + 
             options[i].firstChild.nodeValue + "</li>";
document.getElementById("optionList").innerHTML = output + 
                                                  "</ul>";
  • the i'th item in a collection can be retrieved using array-like indexing
  • firstChild is a property of a node; it returns the first child of the node if it exists, otherwise null
  • nodeValue is a property of a node; it returns the text value if it is a text node, otherwise null
  • an element with textual contents is represented by an element node having a single text node as a child

Using CSS selectors

  • the DOM also provides the methods
    • querySelector
    • querySelectorAll
    which each take a CSS selector as argument
  • querySelector returns the first matching node
  • querySelectorAll returns all matching nodes
  • instead of getElementsByTagName("h1") we could use querySelectorAll("h1")
  • instead of getElementById("optionList") could use querySelector("#optionList")

More complex selectors

  • we could also use selectors
    • div.slide to find all div elements with class value slide
    • div li to find all li elements within div elements
    • div.slide > h1 to find all h1 elements which are children of div elements with class value slide
    • a[href^='http'] to find all a elements with an href attribute whose value starts with http

Adding elements

  • the button is defined as follows:
    <button id="addButton">Add li element</button>
    
  • with click event handler assigned as follows:
    document.getElementById("addButton").onclick = addElement;
    
  • the ul element on this slide is identified by id="target1"

function addElement()

  const elem = document.getElementById("target1");
  const node = document.createElement("li");
  const text = document.createTextNode("Hello");
  node.appendChild(text);
  elem.appendChild(node);
  • appends a new li child to the ul element
  • createElement is a method which creates an element with the given name
  • createTextNode is a method which creates a text node with the given value
  • appendChild is a method of a node; it appends the given node to the list of the node's children

Deleting elements

  • the button is defined as follows:
    <button id="deleteButton">Delete ul element</button>
    
  • with click event handler assigned as follows:
    document.getElementById("deleteButton").onclick = deleteElement;
    
  • the ul element on this slide is identified by id="target2"

function deleteElement()

function deleteElement() {
  const elem = document.getElementById("target2");
  elem.remove();
}
  • deletes the identified ul element
  • remove is a method of a node; it removes the node to which it is applied

jQuery

  • jQuery is a popular JavaScript library which simplifies DOM operations
  • it also takes care of differences among browsers
  • the jQuery file jquery-3.3.1.min.js is referenced by these pages

Using jQuery to delete elements

  • instead of using the deleteElement function, we could use
    function() {$('#target2').remove();}
    
  • jQuery defines the object/function named $
    • which can take a CSS selector as an argument
    • and returns the collection of elements selected
  • the remove method deletes the elements on which it is invoked

Using jQuery to add elements

  • instead of using addElement, we could use
    function() {$('#target1').append($('<li/>', {'text':'Hello'}));}
    
  • the append method adds a new last child to elements on which it is invoked
  • function $ creates a new element when passed a string representing an empty element as first argument
  • the second argument is an object:
    • the text property is interpreted as the textual contents of the element
    • other properties interpreted as attribute names

Finding elements by name (jQuery)

  • using jQuery, the example of finding options could be done as follows:
    $('#optionList').append($('<ul/>'));
    $('option').each(function() {
      $('#optionList > ul').append(
          $('<li/>', {'text': $(this).text()}));
                   });
    
  • each iterates over a set of elements; the function it takes as argument is called for each element
  • this returns the element on which the function is called
  • text returns the textual contents of an element

DOM and XML

  • JavaScript can use DOM to read and navigate XML
  • recall rss-fragment.xml:
    <rss>
      <channel>
        <title> ... </title>
          ...
        <item>
          <title> ... </title>
          <description> ... </description>
          <link> ... </link>
          <pubDate> ... </pubDate>
        </item>
          ...
        <item>
          <title> ... </title>
            ...
        </item>
      <channel>
    </rss>
    

jQuery get method

  • jQuery get method allows you to retrieve a file (e.g., XML, JSON)
  • must be from the same domain as the loaded page (same origin policy)
  • uses the DOM XMLHttpRequest object
  • requests are made asynchronously

Retrieving an XML file

$.get("rss-fragment.xml", 
      function( data ) {
        ...
      },
      "xml"
    );
  • the method takes (at least) 3 arguments:
    • the first is the URL
    • the second is a function to be called on successful retrieval (asynchronous); function is passed the data retrieved (the root of the DOM tree)
    • the third is the type of the data retrieved (XML)

Retrieving RSS item titles

  • say we want to return a list of RSS item titles when the following button is clicked:
  • the id of the above button is listButton
  • there is an empty div element below, with id="Titles"

Code for retrieving item titles

  • in client.js we bind a function name to the click event for the button:
    document.getElementById("listButton").onclick = findItemTitles;
    
  • findItemTitles simply executes the code on the earlier slide where the body of the function is:
    var titles = data.querySelectorAll("item > title")
    var output = "<ul>";
    for ( i = 0; i < titles.length; i++ )
      output = output + "<li>" + titles[i].firstChild.nodeValue + "</li>";
    document.getElementById("Titles").innerHTML = output + "</ul>";
    

Retrieving JSON data

  • consider the following form:
  • say we want to populate the drop-down list of counties/provinces/states by retrieving a list for the selected country from the server
  • we also want to overwrite County/Province/State with the term appropriate for the country selected
  • (Example taken from "Web Development with jQuery" by Richard York, Wrox Press, 2015.)

Form code

  • the code for the form is as follows:
    <form>
      <fieldset>
        <select id='addressCountry'>
          <option value='na'>Please select a country</option>
          <option value='ca'>Canada</option>
          <option value='gb'>United Kingdom</option>
          <option value='us'>United States</option>
        </select>
        <label for='addressState'>County/Province/State:</label>
        <select id='addressState'></select>
      </fieldset>
    </form>
    

JSON country data

  • there are JSON files for each country: ca.json, gb.json and us.json
  • the one for the UK (gb.json) looks as follows:
    {
        "name" : "United Kingdom",
        ... 
        "label" : "County",
        "states" : {
            "0"   : " ",
            "794" : "Angus",
            ...
            "988" : "York"
        }
    }
    
  • label specifies County/Province/State
  • states will be used to populate the drop-down list

Code for JSON retrieval (1)

  • the code is as follows:
      $('#addressCountry').change(
        function() {
          // Remove all of the options
          $('#addressState').empty();
          if (this.value === 'na') return;
          $.getJSON(
              ... see next slide
          );
        }
      );
    
  • change (rather than click) event is needed for select in Chrome and Safari
  • jQuery provides a getJSON function which retrieves a JSON file from the server

Code for JSON retrieval (2)

  • the code for getJSON call is as follows:
          $.getJSON(
            this.value + '.json',
            function(json) {
              // Change the label
              $('label[for="addressState"]').text(
                json.label + ':'
              );
              ... see next slide
            }
          );
    
  • first argument is the name of the file
  • second argument is a function to be called on success and passed the JSON data

Code for JSON retrieval (3)

  • the code for setting the options is as follows:
                $.each(
                  json.states,
                  function(id, state) {
                    ... see next slide
                  }
                );
    
  • each iterates over each key/value pair of states
  • for each one, the function is called and passed the key and value (id and state)

Code for JSON retrieval (4)

  • the code for adding an option is as follows:
                  function(id, state) {
                    $('#addressState').append(
                      $('<option/>')
                        .attr('value', id)
                        .text(state)
                    );
                  }
    
  • a new option is added each time, with its
    • value attribute set to the id of the state and
    • its text set to the value of state

Summary

  • JavaScript
  • HTML events
  • HTML forms
  • JavaScript functions
  • Navigating and manipulating the DOM
  • using jQuery to add, delete and find DOM nodes
  • using jQuery to retrieve XML and JSON files