Session 09 - Javascript, Part 2

Harvard Extension School  
Fall 2021

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

Topics

  1. Javascript - What can you do?
  2. Ice Cream Options
  3. JS Data Structures - array and "object" (key/value pair)
  4. Loops and Iteration
  5. Working with Key/Value objects and Arrays
  6. Responsive Navigation

Session 09 - Javascript, Part 2, slide1
Javascript - What can you do?, slide2
Getting Started with JavaScript, slide3
JavaScript Review, slide4
Ice Cream Options, slide5
Let's Improve on the Ice Cream Example, slide6
Ice Cream Options - select and add click listener improvements, slide7
Ice Cream Options - use JS to hide options, slide8
Ice Cream Options - use classes, slide9
JS Data Structures - array and "object" (key/value pair), slide10
Loops and Iteration, slide11
Javascript and DOM: Building Content, slide12
Javascript and DOM: Building Content, slide13
Javascript and DOM: Building Content, slide14
DOM methods vs innerHTML, slide15
Working with Key/Value objects and Arrays, slide16
Responsive Navigation, slide17
Responsive Navigation, slide18

Presentation contains 18 slides

Javascript - What can you do?

Programmatic access to all aspects of your web page!

Getting Started with JavaScript

JavaScript Review

  1. JS in HTML. Including JavaScript in HTML with script element, with either src attribute or JS code.
    <script src="scripts/site.js" ></script>
    or
    <script>
    /* JS code here */
    console.log('hello from JS!');
    </script>
  2. Variables. Declare variables with let and sometimes const.
    Though you will see the older var, but avoid that.
    You may also see const which declares a constant (a variable that won't be changed).
    let courseName = 'CSCI E-12',
      courseTerm = 'Fall 2021',
      courseInstructor = 'David' ;
  3. Console is your friend. Your browser developer tools will be critical to use, and especially the "Console". Log to the console in JS with
    console.log('hello there!');
  4. When is the code executed?script in head or right before the body close tag.
    But it is good practice to rely on specific events, especially the DOMContentLoaded event!

    The .addEventListener method takes two arguments. The first is the event name as a string, and the second is the function to execute when that event happens.

    window.addEventListener('DOMContentLoaded', function(){
        /* here's where JS goes for when DOM is loaded */
        console.log('the DOM has been loaded and parsed!');
    });
  5. Events - load (and DOMContentLoaded), click, focus, blur, submit, mouseover, mouseout, keypress.
    HTML attributes are available, but don't use these. Add event listeners through JavaScript!
  6. Functions. Functions can be named, and they can also be anonymous (unnamed) when setting event handlers. Functions can have arguements.

    Named function that accepts an argument:

    function square(x) {
      let numberSquared = x*x;
      return numberSquared;
    }

    Anonymous functions — function() {} — are often used in setting event listeners

    window.addEventListener('DOMContentLoaded', function(){
    /* here's where JS goes for when DOM is loaded */
    console.log('the DOM has been loaded and parsed!');
    });
  7. DOM Methods can be used to access the DOM as well as manipulate it! Some common DOM methods are getElementById, getElementsByTagName, createElement, createTextNode, appendChild, and there are others!

Ice Cream Options

ice cream optionsice cream options

Example 9.1 - Ice Cream Options - Example 9.1

 <h3>Ice Cream </h3>
 <form method="post" name="ice_cream" id="ice_cream" action="https://cs12.net/form/submit.php">
   <div>Would you like ice cream?
     <label>
       <input type="radio" name="want" id="ic_yes" value="yes"/>
Yes     </label>
     <label>
       <input type="radio" name="want" id="ic_no" value="no"/>
No     </label>
   </div>
   <fieldset id="icecream_options">
     <legend>Ice Cream Options     </legend>
     <p>Cup or a Cone?
     </p>
     <label>
       <input type="radio" id="container_cup" name="container" value="cup"/>
Cup     </label>
     <label>
       <input type="radio" id="container_cone" name="container" value="cone"/>
Cone     </label>
     <p>Pick your toppings:
     </p>
     <label>
       <input type="checkbox" name="toppings" id="toppings_wc" value="whipcream"/>
Whipped cream     </label>
     <label>
       <input type="checkbox" name="toppings" id="toppings_jimmies" value="jimmies"/>
Jimmies     </label>
     <label>
       <input type="checkbox" name="toppings" id="toppings_sprinkles" value="sprinkles"/>
Sprinkles     </label>
     <label>
       <input type="checkbox" name="toppings" id="toppings_nuts" value="nuts"/>
Nuts     </label>
     <label>
       <input type="checkbox" name="toppings" id="toppings_cherry" value="cherry"/>
Cherry     </label>   </fieldset>
   <p>
     <input type="submit"/>

   </p>
 </form>  

In style element (<style>) within head element:


body {font-family: Calibri,Tahoma,Verdana,Helvetica,sans-serif;}
label { display: block;}

input[type=submit] {display: block; margin-top: 1rem;}

#icecream_options {
  display: none;
  background-color: rgb(238, 238, 238);
  margin-left: 1em;
}

In script element within head element (<script>):


"use strict";

console.log("hello from ice_cream.js");

let inputYes,
    inputNo,
    icoEl;

window.addEventListener('DOMContentLoaded', function(){
    /* here's where JS goes for when DOM is loaded */

    /* add click listener to yes and no */
    inputYes = document.getElementById('ic_yes');
    inputYes.addEventListener('click', function() {
      iceCreamOptionsDisplay();
    } );

    inputNo = document.getElementById('ic_no');
    inputNo.addEventListener('click', function() {
      iceCreamOptionsDisplay();
    });
});


function iceCreamOptionsDisplay() {
    /* function that tests whether 'Yes' or 'No'
       has been selected and sets ice cream option display as needed */
    console.log("in function iceCreamOptionsDisplay");
    icoEl = document.getElementById('icecream_options');
    console.log(icoEl);
    inputYes = document.getElementById('ic_yes');
    if (inputYes.checked == true) {
        icoEl.style.display = 'block';
    } else {
        icoEl.style.display = 'none';
    }
}
 

Let's Improve on the Ice Cream Example

  1. DRY (Don't Repeat Yourself). Instead of selecting input elements separately and adding 'click' listener to each one, can we select the input elements and loop through them?
    Granted, this is somewhat minor, but it is always good to keep "DRY" in mind.
  2. Progressive Enhancement with JS. Let's practice 'progressive enhancement' and use JavaScript to set things up.
    This means we'll have JS hide the options. If, for some reason, JS is broken, then the whole form will be displayed and can be used.
  3. Control presentation through classes, not individual style properties.
    Let's use a class name that controls whether the ice cream options are displayed.

Ice Cream Options - select and add click listener improvements

Starting Point

/* add click listener to yes and no */
inputYes = document.getElementById('ic_yes');
inputYes.addEventListener('click', iceCreamOptionsDisplay );

inputNo = document.getElementById('ic_no');
inputNo.addEventListener('click', iceCreamOptionsDisplay );

Using querySelectorAll and iterate through the list

/* use querySelectorAll and then loop
  through the list using "for (item in list) { }"
  */
inputsWant = document.querySelectorAll("form input[name=want]");
console.log(inputsWant);
for (let input of inputsWant) {
  console.log(input);
  input.addEventListener("click", iceCreamOptionsDisplay);
}
Example 9.2 - Ice Cream Options - Example 9.2

 <h3>Ice Cream </h3>
 <form method="post" name="ice_cream" id="ice_cream" action="https://cs12.net/form/submit.php">
   <div>Would you like ice cream?
     <label>
       <input type="radio" name="want" id="ic_yes" value="yes"/>
Yes     </label>
     <label>
       <input type="radio" name="want" id="ic_no" value="no"/>
No     </label>
   </div>
   <fieldset id="icecream_options">
     <legend>Ice Cream Options     </legend>
     <p>Cup or a Cone?
     </p>
     <label>
       <input type="radio" id="container_cup" name="container" value="cup"/>
Cup     </label>
     <label>
       <input type="radio" id="container_cone" name="container" value="cone"/>
Cone     </label>
     <p>Pick your toppings:
     </p>
     <label>
       <input type="checkbox" name="toppings" id="toppings_wc" value="whipcream"/>
Whipped cream     </label>
     <label>
       <input type="checkbox" name="toppings" id="toppings_jimmies" value="jimmies"/>
Jimmies     </label>
     <label>
       <input type="checkbox" name="toppings" id="toppings_sprinkles" value="sprinkles"/>
Sprinkles     </label>
     <label>
       <input type="checkbox" name="toppings" id="toppings_nuts" value="nuts"/>
Nuts     </label>
     <label>
       <input type="checkbox" name="toppings" id="toppings_cherry" value="cherry"/>
Cherry     </label>   </fieldset>
   <p>
     <input type="submit"/>

   </p>
 </form>  

In style element (<style>) within head element:


body {font-family: Calibri,Tahoma,Verdana,Helvetica,sans-serif;}
label { display: block;}

input[type=submit] {display: block; margin-top: 1rem;}

#icecream_options {
  display: none;
  background-color: rgb(238, 238, 238);
  margin-left: 1em;
}

In script element within head element (<script>):


"use strict";

let inputsWant;
console.log("hello from ice_cream.js");

window.addEventListener("DOMContentLoaded", function () {
  /* here's where JS goes for when DOM is loaded */
  /* add click listener to yes and no input choices
     use "querySelectorAll", which lets us use CSS selectors!
     querySelectorAll returns a list of things that we can
     loop through via 'for ( item of list ) { }'
     */
  inputsWant = document.querySelectorAll("form input[name=want]");
  console.log(inputsWant);
  for (let input of inputsWant) {
    console.log(input);
    input.addEventListener("click", iceCreamOptionsDisplay);
  }
});

function iceCreamOptionsDisplay() {
  let icoEl, inputYes;
  console.log("in iceCreamOptionsDisplay");
  icoEl = document.getElementById("icecream_options");
  console.log(icoEl);
  inputYes = document.getElementById("ic_yes");
  if (inputYes.checked == true) {
    icoEl.style.display = "block";
  } else {
    icoEl.style.display = "none";
  }
}
 

Ice Cream Options - use JS to hide options

Select icecream_options using JS and set display to none.


document.getElementById('icecream_options3').style.display = 'none';
Example 9.3 - Ice Cream Options - Example 9.3

 <h3>Ice Cream </h3>
 <form method="post" name="ice_cream" id="ice_cream" action="https://cs12.net/form/submit.php">
   <div>Would you like ice cream?
     <label>
       <input type="radio" name="want" id="ic_yes" value="yes"/>
Yes     </label>
     <label>
       <input type="radio" name="want" id="ic_no" value="no"/>
No     </label>
   </div>
   <fieldset id="icecream_options3">
     <legend>Ice Cream Options     </legend>
     <p>Cup or a Cone?
     </p>
     <label>
       <input type="radio" id="container_cup" name="container" value="cup"/>
Cup     </label>
     <label>
       <input type="radio" id="container_cone" name="container" value="cone"/>
Cone     </label>
     <p>Pick your toppings:
     </p>
     <label>
       <input type="checkbox" name="toppings" id="toppings_wc" value="whipcream"/>
Whipped cream     </label>
     <label>
       <input type="checkbox" name="toppings" id="toppings_jimmies" value="jimmies"/>
Jimmies     </label>
     <label>
       <input type="checkbox" name="toppings" id="toppings_sprinkles" value="sprinkles"/>
Sprinkles     </label>
     <label>
       <input type="checkbox" name="toppings" id="toppings_nuts" value="nuts"/>
Nuts     </label>
     <label>
       <input type="checkbox" name="toppings" id="toppings_cherry" value="cherry"/>
Cherry     </label>   </fieldset>
   <p>
     <input type="submit"/>

   </p>
 </form>  

In style element (<style>) within head element:


body {font-family: Calibri,Tahoma,Verdana,Helvetica,sans-serif;}
label { display: block;}

input[type=submit] {display: block; margin-top: 1rem;}

#icecream_options3 {
  background-color: rgb(238, 238, 238);
  margin-left: 1em;
}

In script element within head element (<script>):


"use strict";

let inputsWant;
console.log("hello from ice_cream.js");

window.addEventListener("DOMContentLoaded", function () {
  /* here's where JS goes for when DOM is loaded */

  /* select ice cream options and hide */
  document.getElementById('icecream_options3').style.display = 'none';

  /* add click listener to yes and no input choices
     use "querySelectorAll", which lets us use CSS selectors!
     querySelectorAll returns a list of things that we can
     loop through via 'for ( item of list ) { }'
     */
  inputsWant = document.querySelectorAll("form input[name=want]");
  console.log(inputsWant);
  for (let input of inputsWant) {
    console.log(input);
    input.addEventListener("click", iceCreamOptionsDisplay);
  }
});

function iceCreamOptionsDisplay() {
  let icoEl, inputYes;
  console.log("in iceCreamOptionsDisplay");
  icoEl = document.getElementById("icecream_options3");
  console.log(icoEl);
  inputYes = document.getElementById("ic_yes");
  if (inputYes.checked == true) {
    icoEl.style.display = "block";
  } else {
    icoEl.style.display = "none";
  }
}
 

Ice Cream Options - use classes

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

array Example:


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

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" : ['Naval Orange','Tangelo','Clementine','Valencia Orange']
                }
              

Loops and Iteration

let oranges = ['Naval Orange','Tangelo','Clementine','Valencia Orange'];
/* Iterate with for..of */
console.log("Iterate with: item of array");
for (const myorange of oranges) {
   console.log(myorange);
}
console.log("DONE!");

/* Iterate with 'classic' for (i = 0 ; i < LENGTH ; i++) */
console.log("Iterate with classic for i = ;  < ; i++");
for (let i = 0; i < oranges.length; i++ ) {
   console.log(i);
   console.log(oranges[i]);
}
console.log("DONE!");

/* Iterate with '.forEach()' */
console.log("Iterate with forEach()");
oranges.forEach(function(myorange){
  console.log(myorange);
});
console.log("DONE!");

Javascript and DOM: Building Content

DOM create nodes

And do the same for the other three seasons to get:
DOM create nodes

Javascript and DOM: Building Content

Example 9.4 - Example 9.4
 
 <p>
   <button id="makelist" type="submit">Build List of Seasons   </button>
 </p>
 <div id="seasonslist1"> 
 </div>

In script element within head element (<script>):

function makeSeasonsList() {
  let ul_node = document.createElement("ul");

  /* Autumn */
  let li_node1 = document.createElement("li");
  let li_text1 = document.createTextNode("Autumn");
  li_node1.appendChild(li_text1);

  /* Winter */
  let li_node2 = document.createElement("li");
  let li_text2 = document.createTextNode("Winter");
  li_node2.appendChild(li_text2);

  /* Spring */
  let li_node3 = document.createElement("li");
  let li_text3 = document.createTextNode("Spring");
  li_node3.appendChild(li_text3);

  /* Summer */
  let li_node4 = document.createElement("li");
  let li_text4 = document.createTextNode("Summer");
  li_node4.appendChild(li_text4);

  /* Append the list items to the ul */
  ul_node.appendChild(li_node1);
  ul_node.appendChild(li_node2);
  ul_node.appendChild(li_node3);
  ul_node.appendChild(li_node4);

  /* Place on page */
  let container = document.getElementById("seasonslist1");
  container.appendChild(ul_node);
}

/* Wait for DOM to be loaded, then add the click listener
   to the button */
window.addEventListener('DOMContentLoaded',function(){
  document.getElementById('makelist').addEventListener('click', makeSeasonsList);
});
 

Javascript and DOM: Building Content

Using an array (a list).

let seasons = ['Spring', 'Summer', 'Autumn', 'Winter'];

Iterate through Array

Example 9.5 - Example 9.5 | JavaScript example5.js
 
 <p>
   <button id="makelist" type="submit">Build List of Seasons   </button>
 </p>
 <div id="seasonslist2"> 
 </div>

In head element:

<script src="example5.js"> </script>

Contents of example5.js

function makeSeasonsList() {
ul_node = document.createElement("ul");
let seasons = ['Spring', 'Summer', 'Autumn', 'Winter'];
for (let i = 0 ; i < seasons.length ; i++ ) {
  let mytext = i + " " + seasons[i];
  let text_node = document.createTextNode(mytext);
  let li_node = document.createElement("li");
  li_node.appendChild(text_node);
  ul_node.appendChild(li_node);
};
let container = document.getElementById("seasonslist2");
container.appendChild(ul_node);
}
/* Wait for DOM to be loaded, then add the click listener
   to the button */
window.addEventListener('DOMContentLoaded',function(){
  document.getElementById('makelist').addEventListener('click', makeSeasonsList);
});
 

Using forEach array method

Example 9.6 - Example 9.6 | JavaScript example6.js
 
 <p>
   <button id="makelist" type="submit">Build List of Seasons   </button>
 </p>
 <div id="seasonslist3"> 
 </div>

In head element:

<script src="example6.js"> </script>

Contents of example6.js

function makeSeasonsList() {
  ul_node = document.createElement("ul");
  let seasons = ['Spring', 'Summer', 'Autumn', 'Winter'];
  seasons.forEach(function(s){
    let text_node = document.createTextNode(s);
    let li_node = document.createElement("li");
    li_node.appendChild(text_node);
    ul_node.appendChild(li_node);
  });
  let container = document.getElementById("seasonslist3");
  container.appendChild(ul_node);
}

/* Wait for DOM to be loaded, then add the click listener
   to the button */
window.addEventListener('DOMContentLoaded',function(){
  document.getElementById('makelist').addEventListener('click', makeSeasonsList);
});
 

DOM methods vs innerHTML

Working with Key/Value objects and Arrays

Data:

{
  "apples" : ['Macoun','Empire','Honey Crisp','Albemarle Pippin'],
  "oranges" : ['Naval Orange','Tangelo','Clementine','Valencia Orange']
}
Example 9.7 - Example 9.7
 
 <h1>List of Fruits from Data </h1>
 <div id="fruits"><!-- list goes here -->
 </div>

In script element within head element (<script>):

"use strict";

let fruits = {
    "apples": ['Macoun', 'Empire', 'Honey Crisp', 'Albemarle Pippin'],
    "oranges": ['Naval Orange', 'Tangelo', 'Clementine', 'Valencia Orange']
};
window.addEventListener('DOMContentLoaded',function(){
    buildFruitList();
});

function buildFruitList(){
    let fruitList = document.createElement('ul');
    for (const f in fruits) {
        console.log(f);
        let li = document.createElement('li');
        li.appendChild(document.createTextNode(f));
        if (Array.isArray(fruits[f])) {
            console.log(fruits[f]);
            let itemList = document.createElement('ul');
            for (const item of fruits[f]) {
                let li = document.createElement('li');
                li.appendChild(document.createTextNode(item));
                itemList.appendChild(li);
            }
            li.appendChild(itemList);
        }
        fruitList.appendChild(li);
    }
    document.getElementById('fruits').appendChild(fruitList);
}
 

JavaScript:

"use strict";

let fruits = {
    "apples": ['Macoun', 'Empire', 'Honey Crisp', 'Albemarle Pippin'],
    "oranges": ['Naval Orange', 'Tangelo', 'Clementine', 'Valencia Orange']
};
window.addEventListener('DOMContentLoaded',function(){
    buildFruitList();
});

function buildFruitList(){
    let fruitList = document.createElement('ul');
    for (const f in fruits) {
        console.log(f);
        let li = document.createElement('li');
        li.appendChild(document.createTextNode(f));
        if (Array.isArray(fruits[f])) {
            console.log(fruits[f]);
            let itemList = document.createElement('ul');
            for (const item of fruits[f]) {
                let li = document.createElement('li');
                li.appendChild(document.createTextNode(item));
                itemList.appendChild(li);
            }
            li.appendChild(itemList);
        }
        fruitList.appendChild(li);
    }
    document.getElementById('fruits').appendChild(fruitList);
}

Responsive Navigation

menu

menu

menu

Responsive Navigation