CSE 154

Lecture 8: JavaScript and the Document Object Model (DOM)

Today's Agenda

Reminder: Homework 2 due tonight

Creative Project 3

Cloud 9

Modular JavaScript

HTML Form elements

The Document Object Model (DOM) and DOM elements

Getting on your Cloud 9 team

We will be switching to using Cloud9 over the next week because it will be easier to do the server-side programming later in the term. We want you to get used to programming in it sooner rather than later.

You will an email from your TA through Cloud9 with a link to accept an invitation to join the "CSE 154 Spring 2018 - A_ and A_ " team. Accept this invitation and setup an account by doing the following:

  1. Click the link in the email from Cloud9 inviting you
  2. Click 'Create new account' on the Welcome to Cloud9 Teams! page
  3. Type your name in the 'Your Name' field and click 'Next'
  4. Pick a username, type it in the 'username' field, and click 'Next'
  5. Make sure to select 'Student' when it asks 'What kind of developer are you?', and 'Coursework' for 'How will you use Cloud9?' (otherwise, there will be charges if Student is not selected!). Then, click 'Next'
  6. Confirm your details and click 'Next'
  7. Do the captcha if it asks you to, and click 'Create account'
  8. Click 'Join team' when it says 'You have been invited to join team cse154'
  9. Make sure to set your password in the email you will soon receive from Cloud9.
  10. Click the slide below to learn howo to clone the workspace.

Cloning your workspace

  1. Click on the link to your new team subscription on the left hand side ("CSE 154 Spring 2018 - A_ and A_" where the _ are filled in).
  2. Look for the docbrick workspace. Click on the black Clone button.
  3. Give your workspace a name, a description and make sure the team and workspace settings are still correct!
  4. Once you hit the button, you'll go into the Cloud 9 workspace (it takes a little while to set up.

IMPORTANT - Make your Workspace Private.

  1. Go back to your dashboard (Select Cloud9->Dashboard)
  2. Click on the big white square for your workspace, anywhere EXCEPT the the clone or open buttons.
  3. Click on the gear icon
  4. Change your workspace visibility to private and save.

If you do not do that last step you can not guarantee that you work is not plagiarized.

JavaScript Review not Review

JavaScript Review From Lecture 7

Examples of some "less-intuitive" evaluations (from here):

  • 2 < 1 < 2;// true
  • 0 + "1" + 2;// "012"
  • [] + [];// ""
  • "1" / null;// Infinity
  • 0.1 + 0.2 == 0.3;// false

Defining Functions


						function name(params) {
							statement;
							statement;
							...
							statement;
						}
					

JS (template)

						
						function myFunction() {
							console.log("Hello!");
							alert("Your browser says hi!");
						}
					

JS (example)

The above could be the contents of example.js linked to our HTML page

Statements placed into functions can be evaluated in response to user events

Practice: fixErrors2 , containsTwice , functionMystery1 , sumUpTo , veryBestSong

Scoping

Remember that the scope of a variable is the region of a computer program where the variable name may be used.

Recall that it is generally better, for software maintainabilty, to localize your variables, i.e. keep their scope as limited as possible to avoid "side effects" from other parts of the program.

We mentioned the keyword let as a way to declare a variable in the current scope (i.e. between {}'s for instance).

						
						function sayHello(name) {
							let output = "Hello " + name;  // output is local to sayHello
							console.log(output);
						}
					

JS

Example 1: Globals

Globals are variables or symbols that are visible throughout the entire program. They can be bad; other code and other JS files can see and modify them, sometimes unexpectedly!

Example: how many global symbols are introduced by this code? 3 (count, incr, and reset)

							
let count = 0;          // count is a global variable

function incr(n) {      // n is a parameter, local to function incr
    let diez = 10;      // diez is a local variable
    count += n;
}

function reset() {
    count = 0;          // because count is global it can be reset here
    // diez = 0;        // deiz would not be able to be set here.
}

incr(4);
incr(2);
console.log(count);
						

JS

Example 2: Let Variables

let localizes the scope of a variable. Sometimes with interesting results. Example:

							
	let count = 0;          // this count is a global variable

	function incr(n) {
	    let count  = 10;    // this count is a local to incr
	    count += n;
	}


	incr(4);
	incr(2);
	console.log(count);
						

JS

Aside: don't use var

We don't want you using var. Period. Even if you see others use it. Example:

						
	function varTest() {
	    console.log("varTest");
	    var x = 1;
	    if (x === 1) {
	        var x = 2;          // same variable!
	        console.log(x);     // 2
	    }
	    console.log(x);         // 2
	}

	function letTest() {
	    console.log("letTest");
	    let x = 1;
	    if (x === 1) {
	        let x = 2;          // different variable
	        console.log(x);     // 2
	    }
	    console.log(x);         // 1
	}
					

JS

Containing globals in a function

If we enclose the code all in one function, it encloses the scope of all of those symbols into that function.

Example: how many global symbols are introduced by this code? only 1 (everything)
But can we get it to 0?


function everything() {
  let count = 0;

  function incr(n) {
    count += n;
  }

  function reset() {
    count = 0;
  }

  incr(4);
  incr(2);
  console.log(count);
}

everything(); // call the function to run the code
            

JS

Anonymous functions


function(parameters) {
  ... statements ...;
}
          

JavaScript allows you to declare anonymous functions

Quickly creates a function without giving it a name

Can be stored as a variable, attached as an event handler, etc.

The "module pattern"


(function() {
  statements;
})();

Wraps all of your file's code in an anonymous function that is declared and immediately called

0 global symbols will be introduced!

The variables and functions defined by your code cannot be messed with externally

Module pattern example

How many global symbols are introduced in this code?

0 global symbols


(function() {
	let count = 0;

	function incr(n) {
	    count += n;
	}
	function reset() {
	    count = 0;
	}

	incr(4);
	incr(2);
	console.log(count);
})();
            

JavaScript "strict" mode


"use strict";

...your code...
          

JS

Writing "use strict"; at the very top of your JS file turns on strict syntax checking:

  • Shows an error if you try to assign to an undeclared variable
  • Stops you from overwriting key JS system libraries
  • Forbids some unsafe or error-prone language features

You should always turn on strict mode for your code in this class!

JavaScript File Skeleton


/*
 * name
 * Stuff about my file
 */
(function() {

    // phew! your code goes here

})();
            

JS

Take Aways

  • Scoping is ... confusing
  • You might not "get" it until you run into a bug
  • Localize scope
  • Use let vs var
  • Use the module pattern to elimiate global variables

Summary of Java vs. JS vs. Python

Java JS Python
Compiled vs. Interpreted Compiled Interpreted Interpreted
Typing Strong Loose Loose
Variable Declaration Must be declared before use Does not need to be declared before use Does not need to be declared before use
Key Construct Classes (OOP) Function Function

Back to HTML (Briefly!)

<button>

            
              <button id="my-btn">Click me!</button>
          

HTML

output

Button's text appears inside tag; can also contain images

To make a responsive button or other UI control:

  1. Choose the control (e.g., button) and event (e.g., mouse click) of interest
  2. Write a JavaScript function to run when the event occurs
  3. Attach the function to the event on the control

So how did that happen?

First you get the button from the HTML Page

To access an element you use document.getElementById


            let element = document.getElementById("id");
         

JS

document.getElementById returns an object for an element with a given uniqute id in the document.

Note that you omit the # when giving an id in JS

Then handle the click event


            // attaching a named function
            element.onclick = handleFunction;
            function handleFunction() {
              // event handler code

            };
            

JS (onclick template)


            // (alternative) attaching an "anonymous" function
            element.onclick = function() { // attaching onclick function
              // event handler code
            };
          

JS (onclick template)

JavaScript functions can be set as event handlers

When you interact with the element, the function will execute

onclick is just one of many event HTML attributes we'll use

Putting it back together


						<img id="pokeball" src="images/pokeball.jpg" alt="a pokeball" />
						<button id="demo-btn">Click me!</button>
					

HTML

						
						let demoButton = document.getElementById("demo-btn");
						demoButton.onclick = changeImg;

						function changeImage() {
							let pokeballImg = document.getElementById("pokeball");
							pokeballImg.src = "images/mystery.gif";
						}
					

JS

a pokeball

output

The DOM

A tree-shaped structure built out of all of the HTML elements in a page, accessible via JavaScript

Visualizing the tree


            <html>
              <head>
                <title> ... </title>
              </head>
              <body>
                <h1> ... </h1>
                <div>
                  <p> ... </p>
                </div>
              </body>
            </html>
            

HTML

DOM

Document Object Model (DOM)

A set of JavaScript objects that represent each element on the page

Each tag in a page corresponds to a JavaScript DOM object

JS code can talk to these objects to examine elements' state

  • e.g. see whether a box is checked

We can change state

  • e.g. insert some new text into a div

We can change styles

  • e.g. make a paragraph red

The Six Global DOM Objects

Every JavaScript program can refer to the following global objects:

method description
document current HTML page and its content
history list of pages the user has visited
location URL of the current HTML page
navigator info about the web browser you are using
screen info about the screen area occupied by the browser
window the browser window

How to get DOM elements in JS

  1. Ask for them by id: document.getElementyById(...)
  2. Query for them with CSS style selectors:
    • document.querySelector(...)
    • document.querySelectorAll(...)
  3. Make new ones! document.createElement(...)

Example: getting a DOM element in JS


  <p id="october"></p>
          

HTML


  let pTag = document.getElementById("october");
            

JS

What's inside a DOM object?

For starters, the HTML attributes. This HTML:


        <img src="images/puppy.png" alt="A fantastic puppy photo"/>
            

HTML

Has a DOM object (let's call it puppyImg) with these two properties:

  • puppyImg.src -- set by the browser to images/puppy.png
  • puppyImg.alt -- set by the browser to "A fantastic puppy photo"

Accessing Properties of a DOM object (Example)


        <p>See our <a href="sale.html" id="saleslink">Sales</a> today!</p>
        <img id="icon" src="images/borat.jpg" alt="Borat" />
        <caption class="photo user-upload">Beauty.</caption>
        

HTML


let icon    = document.getElementById("icon");
let theLink = document.getElementById("saleslink");
let caption = document.querySelector("caption");
        

JS

Property Description Example
tagName element's HTML tag icon.tagName is "IMG"
className CSS classes of element caption.className is "photo user-upload"
src URL target of an image icon.src is "images/borat.jpg"
href URL target of a link theLink.href is "sale.html"

The innerHTML property

All DOM elements have a property called innerHTML that has the contents of the HTML tag as a string:


					<ul id="dr-seuss">
							<li>Thing 1</li>
							<li>Thing 2</li>
					</ul>
					

HTML


					let elm = document.getElementById("dr-seuss");
					// elm.innerHTML : "\n    <li>Thing 1</li>\n    <li>Thing 2</li>\n"
					

JS

Example using the innerHTML Property


	          
	          Hello 
	          

HTML


	window.onload = function () {
		document.getElementById("output").onclick = addText;
	}
	function addText() {
	  let span = document.getElementById("output");
	  span.innerHTML += " ... goodbye";
	}
	          

JS

Hello

output

Can change the text inside most elements by setting the innerHTML property

Abuse of innerHTML

            
            // bad code quality! Hard to maintain! Prone to bugs!

            let paragraph = document.getElementById("welcome");
            paragraph.innerHTML = "<p>text and <a href=\"page.html\">link</a>";
            

JS

innerHTML can inject arbitrary HTML content into page

However, this is prone to bugs and errors and is considered poor style

  • We do not want you using innerHTML to inject HTML tags; inject plain text only
  • Soon, we'll see a better way to inject content with HTML tags in it

Ok, what do we do with DOM objects?

Set their properties, and the page changes in response

This is how give behavior to web pages: use JavaScript to manipulate the DOM by changing the properties of DOM elements

Modifying DOM Elements (Example)


<a id="fb-link" href="http://www.facebook.com">Facebook</a>
            

HTML

Before the JavaScript runs, we'd see:

And after we run this Javascript:


let link = document.getElementById("fb-link");
link.innerHTML = "MySpace is back in a really big way."
            

JS

We'd see:

Putting it together

Unobtrusive JavaScript

Recall our goal was to keep our web site code "modular" and separated into 3 major categories:

  • content (HTML) - what is it?
  • presentation (CSS) - how does it look?
  • behavior (JavaScript) - how does it respond to user interaction?

What does this mean?

  • HTML with a link to a JavaScript file (in the module pattern) with no JavaScript code inside the <script> tags
  • Use the JS and DOM to attach and execute all JavaScript event handlers

But when does my code run?

<html>
  <head>
    <script src="myfile.js" type="text/javascript"></script>
  </head>
  <body> ... </body>
</html>
        

HTML

let x = 3;
function f(n) { return n + 1; }
function g(n) { return n - 1; }
x = f(x);
            

myfile.js -- JavaScript

Your file's JS code runs the moment the browser loads the script tag

  • Any variables are declared immediately
  • Any functions are declared but not called, unless your global code explicitly calls them

Important! At this point in time, the browser has not yet read your page's body

  • None of the DOM objects for tags on the page have been created yet

A failed attempt at being unobtrusive


<html>
  <head>
    <script src="myfile.js" type="text/javascript"></script>
  </head>
  <body>
    <div><button id="ok">OK</button></div>
    (... more html ...)
            

HTML

let btn = document.getElementById("ok");
btn.onclick = okayClick;  // this is bad: btn is null at this point
            

myfile.js -- JavaScript

Problem: global JS code runs the moment the script is loaded

Script in head is processed before page's body has loaded

No elements are available yet or can be accessed yet via the DOM

We need a way to attach the handler after the page has loaded...

The window.onload event

function functionName() {
  // put code to initialize the page here
}

// instruct window to run the function when the page has loaded:
  window.onload = functionName;
          

JS (template)

There is a global event called window.onload event that happens once everything in the page has been loaded

If you attach a function as a handler for window.onload, it will run at that time

How an event is handled


<button id="ok">OK</button>   <!-- (1) -->
            

HTML


// called when page loads; sets up event handlers
function pageLoad() {
  let ok = document.getElementById("ok");   // (3)
  ok.onclick = okayClick;
}

function okayClick() {
  alert("booyah");                          // (4)
}

window.onload = pageLoad;                   // (2)
            

JS

JS Skeleton

Download template.js (and rename it) as a starting point




            

HTML


(function() {
  window.onload = function() {
    // phew! your code goes here
  };
})();
            

JS

Common Unobtrusive JS Errors

event names are all lowercase, not capitalized like most variables


// window.onLoad = pageLoad;   // WRONG!!!
window.onload = pageLoad;      // right!
            

JS

you shouldn't write () when attaching the handler

(if you do, it calls the function immediately, rather than setting it up to be called later)


// ok.onclick = okayClick();       // WRONG!!!
ok.onclick = okayClick;            // right!
            

JS

The JSLint checker will catch this mistake

Related: can't directly call functions like alert; must enclose in your own function


// ok.onclick = alert("booyah");     //WRONG!!!

ok.onclick = okayClick;              // right
function okayClick() { alert("booyah"); }
          

JS

Anonymous function example


window.onload = function() {
  let ok = document.getElementById("ok");
  ok.onclick = okayClick;
};

function okayClick() {
  alert("booyah");
}
            

JS

or, the more concise, but perhaps harder to read:

window.onload = function() {
            document.getElementById("ok").onclick = function() {
                alert("booyah");
            };
        };
            

Unobtrusive styling


function okayClick() {
  this.style.color = "red";       // <-- bad style
  this.className = "highlighted"; // <-- better style
}
            

HTML

.highlighted { color: red; }
            

CSS

Well-written JavaScript code should contain as little CSS as possible

Use JS to set CSS classes/IDs on elements

Define the styles of those classes/IDs in your CSS file

Wat?

This is worth 3 minutes of your viewing pleasure.