Session 09 - Javascript, Part 2

Harvard Extension School  
Spring 2022

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
JS Data Structures - array and "object" (key/value pair), slide6
Loops and Iteration, slide7
querySelector and querySelectorAll, slide8
Let's Improve on the Ice Cream Example, slide9
Ice Cream Options - select and add click listener improvements, slide10
Javascript and DOM: Building Content, slide11
Javascript and DOM: Building Content, slide12
Javascript and DOM: Building Content, slide13
DOM methods vs innerHTML, slide14
Working with Key/Value objects and Arrays, slide15
Responsive Navigation, slide16
Responsive Navigation, slide17

Presentation contains 17 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 = 'Spring 2022',
      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.

    document.addEventListener('DOMContentLoaded', function(){
        /* here's where JS goes for when DOM is loaded */
        console.log('the DOM has been loaded and parsed!');
    });
  5. Events - many are user-driven such as click, focus, blur, submit, mouseover, mouseout, keypress.
    And one important one happens when the browser has processed and loaded the HTML DOM — DOMContentLoaded.
    Even listeners are added 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

    document.addEventListener('DOMContentLoaded', function(){
      /* here's where JS goes for when DOM is loaded */
      console.log('the DOM has been loaded and parsed!');
    });
  7. JavaScript gives us ways to access the DOM as well as manipulate it! Some common ways of accessing the DOM are getElementById, querySelector, querySelectorAll as well as classList, classList.add, classList.remove, classList.toggle.
    We can also construct content with methods like createElement, createTextNode, appendChild, and innerHTML

Ice Cream Options

ice cream optionsice cream options

Example 9.1 - Ice Cream Options - Example 9.1

 <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>
   <button type="submit">Submit Order   </button>
 </form>  

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

#icecream_options {  background-color: rgb(238, 238, 238);
  padding: 1rem;
  margin-top: 1rem;
  display: block;
} #icecream_options.hide { display: none; }
label { display: block; }

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


document.addEventListener("DOMContentLoaded", function() {
  console.log('dom is loaded!');
   let icOptions = document.getElementById('icecream_options');
   console.log(icOptions);

   icOptions.classList.add('hide');

   let yesRadio = document.getElementById('ic_yes');

   yesRadio.addEventListener('click', function(){
       /* remove "hide" class from icecream_options */
       if (yesRadio.checked == true) {
           icOptions.classList.remove('hide');
       }
   });

   let noRadio = document.getElementById('ic_no');
   noRadio.addEventListener('click',function(){
       /* add 'hide' class */
       if (noRadio.checked == true) {
           icOptions.classList.add('hide');
       }
   });
});

}
 

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!");

querySelector and querySelectorAll

Let's Improve on the Ice Cream Example

  1. Progressive Enhancement with JS. Good news! We are already doing 'progressive enhancement' and using JavaScript to set things up (using JS to "hide" the options when the page loads). If, for some reason, JS is broken, then the whole form will be displayed and can be used.
  2. DRY (Don't Repeat Yourself) — use loops! Instead of selecting input elements separately and adding 'click' listener to each one as well as the logic of showing or hiding options, can we select the input elements and loop through them?
  3. DRY (Don't Repeat Yourself) — use functions!

Ice Cream Options - select and add click listener improvements

Starting Point

document.addEventListener('DOMContentLoaded',function(){
    console.log('dom is loaded!');
    let icOptions = document.getElementById('icecream_options');
    console.log(icOptions);

    icOptions.classList.add('hide');

    let yesRadio = document.getElementById('ic_yes');
    yesRadio.addEventListener('click', function(){
        /* remove "hide" class from icecream_options */
        if (yesRadio.checked == true) {
            icOptions.classList.remove('hide');
        }
    });

    let noRadio = document.getElementById('ic_no');
    noRadio.addEventListener('click',function(){
        /* add 'hide' class */
        if (noRadio.checked == true) {
            icOptions.classList.add('hide');
        }
    });

})

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", function(){...});
}
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: block;
  background-color: rgb(238, 238, 238);
  margin-left: 1em;
}
#icecream_options.hide {
  display: none;
}

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


"use strict";

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

document.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, radioYes;
  console.log("in iceCreamOptionsDisplay");
  icoEl = document.getElementById("icecream_options");
  console.log(icoEl);
  radioYes = document.getElementById("ic_yes");
  if (radioYes.checked == true) {
    icoEl.classList.remove('hide');
  } else {
    icoEl.classList.add('hide');
  }
}
 

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.3 - Example 9.3
 
 <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 */
document.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.4 - Example 9.4 | JavaScript example4.js
 
 <p>
   <button id="makelist" type="submit">Build List of Seasons   </button>
 </p>
 <div id="seasonslist2"> 
 </div>

In head element:

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

Contents of example4.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 */
document.addEventListener('DOMContentLoaded',function(){
  document.getElementById('makelist').addEventListener('click', makeSeasonsList);
});
 

Using forEach array method

Example 9.5 - Example 9.5 | JavaScript example5.js
 
 <p>
   <button id="makelist" type="submit">Build List of Seasons   </button>
 </p>
 <div id="seasonslist3"> 
 </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'];
  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 */
document.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.6 - Example 9.6
 
 <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']
};
document.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']
};
document.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