Session 12 - JavaScript, Part 5

Harvard Extension School  
Spring 2022

Course Web Site: https://cscie12.dce.harvard.edu/

Topics

  1. JavaScript and "Ajax"
  2. JS Data Structures - array and "object" (key/value pair)
  3. Ajax - Getting JSON from HTTP request
  4. Same Origin Policy and CORS
  5. Javascript Helping with Navigation
  6. Final Project - Skeleton
  7. Surface

Session 12 - JavaScript, Part 5, slide1
JavaScript, slide2
JavaScript and "Ajax", slide3
A Collection of Technologies, slide4
What can you do with Ajax/XHR?, slide5
JS Data Structures - array and "object" (key/value pair), slide6
Ajax - Getting JSON from HTTP request, slide7
Let's Try It Out!, slide8
Apples, slide9
Apples, slide10
MLB, slide11
MLB - XHR, slide12
MLB - fetch, slide13
MLB - getJSON with jQuery, slide14
National Park Service API, slide15
Same Origin Policy and CORS, slide16
Same Origin Policy, slide17
CORS - Cross Origin Resource Sharing, slide18
JavaScript to Submit a Form, slide19
Javascript Helping with Navigation, slide20
Various Forms of Navigation, slide21
Some navigation systems illustrated, slide22
Navigation , slide23
"You are here" with CSS, slide24
"You are here" with JavaScript, slide25
Pages from Parts and Clamshell Navigation, slide26
Final Project - Skeleton, slide27
Page Components, slide28
Wireframes and Sketches - "Low" to "High" Fidelity, slide29
Surface, slide30
Non-Designer's Design Book, slide31
Non-Designer's Design Book, slide32
Colors, slide33
Home Page -- Don't Make Me Think (Steven Krug), slide34
Don't make me think, slide35

Presentation contains 35 slides

JavaScript

JavaScript and "Ajax"

ajax

XHR/Ajax flow:
web_schematic_ajax.png

  1. The browser makes an HTTP GET request for the search page
  2. The server responds with the HTML content.
    Note that we are not showing browser requests for other page resources such as image, CSS, or JavaScript files
  3. The user types in a search term and clicks the submit button (or presses "enter")
  4. A JavaScript event handler is triggered on the form submit, and JavaScript sends an HTTP request via the browser to the server. This HTTP request contains the search term typed in by the user as a parameter sent to the server
  5. A program on the server searches the course database for any courses that contain the search term.
  6. The program (via the web server) returns the matching courses in a data format to the browser (typically in JSON format)
  7. The browser receives the data, hands it off to the JavaScript, and the JavaScript formats the data into HTML and updates the search area on the page

What the browser does

What the server does

The server is simply responding to HTTP requests, and sending responses back to the browser. The "how" of looking up courses in a database based on a keyword search term is beyond the scope of this lesson -- we will demystify that part later in the course.

A Collection of Technologies

So we see Ajax is really a collection of technologies that are working together to send and receive data to and from the web server based on user actions, and to format and display this data to the user.

Some of the key technologies involved are:

What can you do with Ajax/XHR?

JS Data Structures - array and "object" (key/value pair)

JSON - JavaScript Object Notation

JSON array Example:


         ['Autumn', 'Winter', 'Spring', 'Summer']
       

JSON object Examples:

Simple "name/value" pairs:


         {
           "lastName" : "Bacow",
           "firstName" : "Lawrence",
           "email" : "president@harvard.edu"
         }
       

"name/value" pairs, with values being an array (list) of things:


         {
           "apples" : ['Macoun','Empire','Honey Crisp','Albemarle Pippin'],
           "oranges" : ['Navel Orange','Tangelo','Clementine','Valencia Orange']
         }
       

More about JSON

A data format widely used in Ajax is JSON -- this format is used to pass data from the web server to the browser, and it is in a format that is easily worked with in JavaScript.

We first need to take a look at the JSON format and how we can work with it, and then we'll see how this works together in Ajax.

The introduction to JSON from json.org is a great place to start:

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.

JSON is built on two structures:

These are universal data structures. Virtually all modern programming languages support them in one form or another. It makes sense that a data format that is interchangeable with programming languages also be based on these structures.

There are several online JSON viewers and validators you can use that are helpful for exploring, writing, or validating JSON structures:

Ajax - Getting JSON from HTTP request

XHR - XMLHttpRequestObject

Javascript "fetch"

fetch(url).then(response => response.json()).then(data => processData(data));

jQuery

jQuery makes this easier with the ".getJSON" method!

Let's Try It Out!

Apples


You may find a "JSON Viewer" plugin or extension for your browser useful if you work with JSON
json

Apples

The JavaScript:

let applesUrl = "https://cscie12.dce.harvard.edu/apples-pyo.php";
document.addEventListener('DOMContentLoaded',function(){
  fetch(applesUrl)
    .then(response => response.json())
    .then(data => buildApplesList(data));
});

function buildApplesList(data){
  let template = document.getElementById('apple-template').innerHTML ;
  console.log(template);
  let compiledTemplate = Handlebars.compile(template);
  let rendered = compiledTemplate(data);
  document.getElementById('applelist').innerHTML = rendered;
}

The template:

<template id="apple-template">
<h2>Picking Now</h2>
  <ul>
    {{#apples.picking_now}}
      <li>{{ . }}
    {{/apples.picking_now}}
  </ul>

  <h2>Picking Soon</h2>
  <ul>
    {{#apples.picking_soon}}
      <li>{{ . }}
    {{/apples.picking_soon}}
  </ul>
</template>

MLB

MLB Data from mlbapidata: https://statsapi.mlb.com/api/v1/teams?sportId=1

Here's a snippet of JSON:


{
  "id": 144,
  "name": "Atlanta Braves",
  "link": "/api/v1/teams/144",
  "season": 2021,
  "venue": {
    "id": 4705,
    "name": "Truist Park",
    "link": "/api/v1/venues/4705"
  },
  "springVenue": {
    "id": 5380,
    "link": "/api/v1/venues/5380"
  },
  "teamCode": "atl",
  "fileCode": "atl",
  "abbreviation": "ATL",
  "teamName": "Braves",
  "locationName": "Atlanta",
  "firstYearOfPlay": "1871",
  "league": {
    "id": 104,
    "name": "National League",
    "link": "/api/v1/league/104"
  },
  "division": {
    "id": 204,
    "name": "National League East",
    "link": "/api/v1/divisions/204"
  },
  "sport": {
    "id": 1,
    "link": "/api/v1/sports/1",
    "name": "Major League Baseball"
  },
  "shortName": "Atlanta",
  "franchiseName": "Atlanta",
  "clubName": "Braves",
  "springLeague": {
    "id": 115,
    "name": "Grapefruit League",
    "link": "/api/v1/league/115",
    "abbreviation": "GL"
  },
  "allStarStatus": "N",
  "active": true
},

MLB - XHR

/* mlb api;  sportId = 1 is major league */
let urlTeams = "https://statsapi.mlb.com/api/v1/teams?sportId=1",
  xhr = new XMLHttpRequest();

document.addEventListener("DOMContentLoaded", function () {
  console.log("dom ready");
  xhr.responseType = "json";
  xhr.open("GET", urlTeams);
  xhr.addEventListener("load", buildList);
  xhr.send();
});

function buildList() {
  let teams = xhr.response.teams;
  teams.sort((a, b) => (a.name > b.name ? 1 : -1));
  let teamlist = document.createElement("ul");
  for (const team of teams) {
    console.log(team);
    console.log(team.name);
    let myli = document.createElement("li");
    let myanchor = document.createElement("a");
    let mytext = document.createTextNode(team.name);
    let teamUrlPath = team.teamName.toLowerCase().replace(" ", "");
    let myteamhref = "https://mlb.com/" + teamUrlPath;
    myanchor.setAttribute("href", myteamhref);
    teamlist.appendChild(myli).appendChild(myanchor).appendChild(mytext);
  }
  document.getElementById("teamscontainer").appendChild(teamlist);
}

MLB - fetch

/* mlb api;  sportId = 1 is major league */
let urlTeams = "https://statsapi.mlb.com/api/v1/teams?sportId=1";

document.addEventListener("DOMContentLoaded", function () {
  fetch(urlTeams)
    .then((response) => response.json())
    .then((data) => buildList(data.teams));
});

MLB - getJSON with jQuery

$.getJSON

/* mlb api;  sportId = 1 is major league */
let urlTeams = "https://statsapi.mlb.com/api/v1/teams?sportId=1";

$(document).ready(function () {
  $.getJSON(urlTeams, buildList);
});

National Park Service API

nps

Approach:

Same Origin Policy and CORS

When working with XHR/Ajax, it is important to understand some basic concepts of web application security. Some concepts we'll briefly describe are:

These are important to understand since the browser restricts the XHR calls allowed.

Same Origin Policy

This is the simplest policy, and will cover all cases where the data you are requesting comes from the same hostname as the page making the request.

Under the same origin policy, a web browser will permit JavaScript contained in a web page to access data from the same origin -- or the same "hostname" of the URL.

So if your JavaScript and the data it is accessing all come from the same origin (hostname in the URL), the browser will permit this communication.

If the JavaScript and the data come from different origins (hostnames), then the browser will block this for security reasons.


For JavaScript to access data that comes from different origins, you'll need to make sure CORS headers are set correctly.

CORS - Cross Origin Resource Sharing

CORS is a common and preferred method for handling cross-origin requests.

Using CORS, it is possible for the browser and server to determine whether or not to allow a cross-origin request. This happens as part of the HTTP request. The server can specify access control rules, which a browser will then use to determine whether a cross-origin request is permitted.

We won't go into how make the server-side CORS compatible right now. From the front-end perspective, it is enough to understand that you are using a CORS-enabled service. You don't need to do anything to enable CORS from within your JavaScript -- it already is there and is used by the browser.

HTTP response header:
access-control-allow-origin: *

For example, the service from "cdn.rawgit.com" (e.g. apples.json) uses CORS, which is why the "Pick Your Own Apples" example worked fine, despite the different origins between the page the JSON.

MDN: Cross-Origin Resource Sharing

JavaScript to Submit a Form

document.addEventListener("DOMContentLoaded",function(){
    let form = document.getElementById('comment-form');
    form.addEventListener("submit",function(ev){
        ev.preventDefault();
        sendData(form);
    });
});

function sendData(form) {
    const xhr = new XMLHttpRequest();

    // Bind the FormData object and the form element
    const fd = new FormData( form );

    // Define what happens on successful data submission
    xhr.addEventListener( "load", function(ev) {
        console.log(ev.target.responseText);
        form.innerHTML = 'Thank you for your feedback.';
    } );

    // Define what happens in case of error
    xhr.addEventListener( "error", function( ev ) {
        console.log('Oops! Something went wrong.');
    } );

    // Set up our request
    xhr.open( form.getAttribute('method'), form.getAttribute('action') );

    // The data sent is what the user provided in the form
    xhr.send( fd );
}

Javascript Helping with Navigation

We can use JavaScript to make sure we have the right navigation for the page!

Web Navigation Systems

Don't Make Me Think: Navigation

Various Forms of Navigation

Harvard College

Some navigation systems illustrated

Breadcrumb, Clamshell, Tab / Horizontal List, Dropdown

harvard university navigation

Navigation

Iroquois Constitution

<html>
  <head>
    <title>The Great Binding Law, Gayanashagowa (Constitution of the Iroquois Nations)</title>
    <link rel="stylesheet"  href="style.css" />
  </head>
  <body id="part1">
    <?php include("inc/header.php"); ?>
    <?php include("inc/nav.php"); ?>
    <main>
      <?php include("inc/content1.php"); ?>
    </main>
    <?php include("inc/footer.php"); ?>
  </body>
</html>

"You are here" with CSS

"You are Here" CSS Example in JSFiddle

you are here

<nav id="navigation">
  <ul id="mainnav">
    <li id="navpart1"><a href="1.shtml">The Great Binding Law, Gayanashagowa</a></li>
    <li id="navpart2"><a href="2.shtml">Rights, Duties and Qualifications of Lords</a></li>
    <li id="iamhere"><a href="3.shtml">Election of Pine Tree Chiefs</a></li>
    <li id="navpart4"><a href="4.shtml">Names, Duties and Rights of War Chiefs</a></li>
    <li id="navpart5"><a href="5.shtml">Clans and Consanguinity</a></li>
    <li id="navpart6"><a href="6.shtml">Official Symbolism</a></li>
    <li id="navpart7"><a href="7.shtml">Laws of Adoption</a></li>
    <li id="navpart8"><a href="8.shtml">Laws of Emigration</a></li>
    <li id="navpart9"><a href="9.shtml">Rights of Foreign Nations</a></li>
    <li id="navpart10"><a href="10.shtml">Rights and Powers of War</a></li>
    <li id="navpart11"><a href="11.shtml">Treason or Secession of a Nation</a></li>
    <li id="navpart12"><a href="12.shtml">Rights of the People of the Five Nations</a></li>
    <li id="navpart13"><a href="13.shtml">Religious Ceremonies Protected</a></li>
    <li id="navpart14"><a href="14.shtml">The Installation Song</a></li>
    <li id="navpart15"><a href="15.shtml">Protection of the House</a></li>
    <li id="navpart16"><a href="16.shtml">Funeral Addresses</a></li>
  </ul>
</nav>

And the CSS:

#navigation a {
  /* Rules for navigation items */
}
#navigation a:hover {
  /* Rules for navigation items */
}

/* Rules specific for "you are here" */
#navigation #iamhere a,
#navigation #iamhere a:hover {
  /* Rules for the "you are here" item */
}

"You are here" with JavaScript

View this technique in action.
Example in JSFiddle

  1. Each body is uniquely identified (id)
  2. Each navigation list item gets an id
  3. CSS rule for id="iamhere"
  4. JavaScript to set the "iamhere" id

Note the id of the body:

<html>
<head>
    <title>Election of Pine Tree Chiefs (Constitution of the Iroquois Nations)</title>
    <link rel="stylesheet"  href="style.css" />
  </head>
  <body id="part3">
    <?php include("inc/header.php"); ?>
    <?php include("inc/nav.php"); ?>
    <main>
      <?php include("inc/content3.php"); ?>
    <main>
    <?php include("inc/footer.php"); ?>
  </body>
</html>

Each navigation item has an id:

<nav id="navigation">
  <ul id="mainnav">
    <li id="navpart1"><a href="1.shtml">The Great Binding Law, Gayanashagowa</a></li>
    <li id="navpart2"><a href="2.shtml">Rights, Duties and Qualifications of Lords</a></li>
    <li id="navpart3"><a href="3.shtml">Election of Pine Tree Chiefs</a></li>
    <li id="navpart4"><a href="4.shtml">Names, Duties and Rights of War Chiefs</a></li>
    <li id="navpart5"><a href="5.shtml">Clans and Consanguinity</a></li>
    <li id="navpart6"><a href="6.shtml">Official Symbolism</a></li>
    <li id="navpart7"><a href="7.shtml">Laws of Adoption</a></li>
    <li id="navpart8"><a href="8.shtml">Laws of Emigration</a></li>
    <li id="navpart9"><a href="9.shtml">Rights of Foreign Nations</a></li>
    <li id="navpart10"><a href="10.shtml">Rights and Powers of War</a></li>
    <li id="navpart11"><a href="11.shtml">Treason or Secession of a Nation</a></li>
    <li id="navpart12"><a href="12.shtml">Rights of the People of the Five Nations</a></li>
    <li id="navpart13"><a href="13.shtml">Religious Ceremonies Protected</a></li>
    <li id="navpart14"><a href="14.shtml">The Installation Song</a></li>
    <li id="navpart15"><a href="15.shtml">Protection of the House</a></li>
    <li id="navpart16"><a href="16.shtml">Funeral Addresses</a></li>
  </ul>
</nav>

And the CSS:

#navigation a {
      /* Rules for navigation items */
    }
    #navigation a:hover {
      /* Rules for navigation items */
    }

    /* Rules specific for "you are here" */
    #navigation #iamhere a,
    #navigation #iamhere a:hover {
      /* Rules for the "you are here" item */
    }

And the JavaScript (using jQuery) that finds the correct navigation item and sets the id attribute value to "iamhere":

document.addEventListener('DOMContentLoaded',function(){
	console.log("Ready!");
  let mybodyid = document.querySelector('.this_should_be_the_body').getAttribute('id');
  let mynavid = '#nav' + mybodyid;
  /* e.g. for 3.shtml:
      mybodyid is 'part3'
      mynavid  is '#navpart3'
   */
  document.querySelector(mynavid).setAttribute('id','iamhere');
});

Pages from Parts and Clamshell Navigation

Here we take advantage of CSS selectors in JQuery, along with "parents" and "children" and "show" and "hide" methods.

clamshell

$(document).ready(function(){
      console.log("Ready!");
      var mybodyid = $('body').attr('id');
      var mynavid = '#nav_' + mybodyid;
      console.log("mybodyid is " + mybodyid);
      console.log("mynavid is " + mynavid);

      // Set iamhere id
      $(mynavid).attr('id','iamhere');

      // hide all nested lists
      $('#navigation ul ul').hide();

      // show parents of "iamhere"
      $('#iamhere').parents().show();

      // show children of "iamhere"
      $('#iamhere').children().show();
});

JSFiddle Example

Note for the JSFiddle example, we are using a 'div' to contain the 'id' instead of the 'body'.
Clamshell Navigation in JS Fiddle

Files

Final Project - Skeleton

Skeleton

Page Components

Wireframes and Sketches - "Low" to "High" Fidelity

Tools to consider:

Sketches

wireframe

Wireframes

wireframe

wireframe


Wireframes - Drawing and prototype

wireframe

prototype

Surface

Surface

Non-Designer's Design Book

Good Design is as Easy as 1, 2, 3
Good Design is as Easy as 1, 2, 3

non-designer's design book
The non-designer's design book
by Robin Williams

Non-Designer's Design Book

Four Basic Principles
non-designer's design book
The non-designer's design book
by Robin Williams

Colors


Creating Color Palettes:

Home Page -- Don't Make Me Think (Steven Krug)

Don't make me think

Don't Make Me Think
Don't make me think, revisited : a common sense approach to Web usability
by Steve Krug


Three Princples of Usability