CSE 154

Section 3: Introduction to JavaScript

Today's Agenda

Experience common JavaScript bugs

Review helpful debugging strategies

Learn how to write a JavaScript function

Learn how to update page content/style with JavaScript (if time)

Section Goals

By the end of this section, you should be able to:

  • Develop a basic JavaScript debugging strategy
  • Identify and fix common JavaScript bugs with debugging strategies
  • Be able to write a JavaScript file and link it to HTML
  • Be able to write JavaScript functions which update a page's content/style

Debugging

JavaScript is notoriously difficult to debug due to its lack of error messages. We will go over some strategies in today's lab, but more debugging strategies can be found below. We strongly recommend you read through these, for easier debugging in future assignments.

Useful Debugging Tools

There are several tools that are available to help debug JavaScript programs. For Firefox, the built-in Web Inspector is a popular in-browser debugging tool. For Chrome, Chrome Dev Tools are a popular choice (the Chrome Inspector tool is included with Chrome, and can be opened using Ctrl+I on Windows/Linux).

Validator tools are also useful for debugging JavaScript, and can detect common syntax errors that would otherwise be hard to find manually. You may find the W3C HTML Validator or JSLint helpful for finding errors in your HTML or JavaScript code.

Debugging JS code in Chrome

Chrome JS Debugging (start)

Chrome's Web Inspector debugger can set breakpoints, step through code, examine values (Sources tab)

The interaction pane for typing in arbitrary JS expressions (Console tab; Sources tab with code and variable views [see screenshot])

Try it on your own with this example (from the screenshots)!

Debugging in Progress

Chrome debugging finished

Debugging Finished

Chrome debugging finished

JSLint

JSLint

JSLint: an analyzer that checks your JS code, much like a compiler, and points out common errors

When your JS code doesn't work, paste it into JSLint first to find many common problems

JavaScript "strict" mode

              
                "use strict";
                
                your code...
              
            

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

  • Shows an error if you try to assign 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

Other Debugging Strategies

alert() and console.log() are useful to include in functions that you are trying to debug, and are probably going to be most helpful when debugging JavaScript in this class.

A good strategy is to start with one of these functions in the top of your .js file as a sanity check that your script was correctly linked to the HTML page. Then, add it to the first function that is called to check that the function was called correctly, and continue the process until you reach the line(s) of code that are not working as expected.

You may find it useful to pass in variable values throughout this process so that you can check whether your variables (e.g., text in an HTML tag or value in a <input> tag have the correct values.

Debugging Checklist

  • Are you sure the browser is even loading your JS file at all?
    Put an alert at the top of it and make sure it appears.
  • When you change your code, do a full browser refresh (Shift-Ctrl-R)
  • Chrome JS error Check bottom-right corner of Chrome console panel for syntax errors.
  • Paste your code into our JSLint tool to find problems.
  • Type some test code into Chrome's console or use a breakpoint.

General Good Coding Practices

ALWAYS code with Firefox / Chrome console open

Incremental development: code a little, test a little

Follow good general coding principles:

  • Remove redundant code
  • Make each line short and simple

Use lines and variables liberally:

  • It's good to save parts of a complex computation as variables
  • Helps to see what part of a long expression was bad/undefined/etc.

Don't fear the Firefox/Chrome debugger

Event-Driven Programming

event-driven programming

Unlike Java programs, JS programs have no main; they respond to user actions called events

Event-Driven Programming: writing programs driven by user events

Handling Events


            // attaching a named function
            element.onclick = handleFunction;
            let handleFunction = function() { // attaching onclick function
              // 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

Accessing an Element: document.getElementById


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

JS

document.getElementById returns the DOM object for an element with a given id (note that you omit the # when giving an id)

Back to HTML with Buttons: <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

onclick Event Handler: an Example


            <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

Putting it All Together

We'll learn more about this tomorrow, but in order to actually access any tags on the page with JavaScript, we need to wrap the event handlers in the page window's onload event handler

Similar to how onclick is used to attach to a tag and listen for a click event, onload is used to attach to the window and listen for a signal that the page "is loaded". When the page is loaded, everything in the window.onload function is then executed, including any onclick attachments!


          // listener attached before page is loaded
          window.onload = function() {
            // this code is "unlocked" after page is loaded! 
            document.getElementById("my-id").onclick = myClickEventHandler;
          };

          function myClickEventHandler() {
            // this code is "unlocked" after the button is clicked!
            alert("Hi!");
          }
          

JS (example)

Exercise 1: Buggy JavaScript

The following pages have mistakes that cause their JavaScript code not to work properly. Look at the pages, find the mistakes, and correct the problems.

  1. Buggy Page #1: HTML | JavaScript
  2. Buggy Page #2: HTML | JavaScript
  3. Buggy Page #3: HTML | JavaScript
  4. Buggy Page #4: HTML | JavaScript

Exercise 1: Solution

You can find the bugs in the comments of each (fixed) HTML/JS file:

  1. Buggy Page #1: HTML | JavaScript
  2. Buggy Page #2: HTML | JavaScript
  3. Buggy Page #3: HTML | JavaScript
  4. Buggy Page #4: HTML | JavaScript

Exercise 2: cRaZyCaPs

With the Chrome or Firefox console open, write a function named crazyCaps that accepts a string as a parameter and returns a new string with its capitalization altered such that the characters at even indexes are all in lowercase and odd indexes are all in uppercase.

For example, if a variable str stores "Hey!! THERE!", the call of crazyCaps(str) should return "hEy!! tHeRe!".

Exercise 2: Solution


function crazyCaps(s) {
  let result = "";
  for (let i = 0; i < s.length; i++) {
    if (i % 2 == 0) {
      result += s[i].toLowerCase();
    } else {
      result += s[i].toUpperCase();
    }
  }
  return result;
}
            

JS

Exercise 3: What's Your Color?

We've provided an HTML file colorifyme.html and a start to a JavaScript file colorify.js that it links to. Download both files and fill in the "TODO" comments of colorify.js so that when the web page's "colorify" button is clicked, it randomly decides the color of the page background. That is, it should choose a random hex value for the background between #000000 and #FFFFFF. In addition, it should replace any text in the heading tag that has the ID "my-color" with the text, "Your color is RANDOMCOLOR", (where RANDOMCOLOR is the hex value randomly-generated for the background).

A runnable solution is located here (don't peek at the solution code!)

Exercise 3: Solution


"use strict";
window.onload = function() {
  document.getElementById("colorify").onclick = changeBackgroundColor;
};

function changeBackgroundColor() {
  let colorOptions = ["0", "1", "2", "3", "4", "5", "6", "7",
                      "8", "9", "A", "B", "C", "D", "E", "F"]; 
  let randomColor = "#";
  for (let i = 0; i < 6; i++) {
    randomColor += colorOptions[Math.floor(Math.random() * 16)];
  }
  document.body.style.backgroundColor = randomColor;
  document.getElementById("my-color").innerText = "Your color is " + randomColor + "!";
}
              

JS

Exercise 4: Weight Conversion

Create the file conversions.js which is referenced by conversions.html. Write a function convert() in conversions.js that takes the value in the text input and converts it from either kilograms (kg) to pounds (lb) or from pounds to kilograms, depending on the value selected in the dropdown box.

The result should be displayed in the empty span with the id of #answer.

The conversion factor from pounds to kilograms is 0.45359237, and the conversion factor from kilograms to pounds is 2.20462262.

You should edit the HTML file conversions.html to add id's to the elements as necessary and you may assume valid input. A runnable version of the solution can be found here (don't peek at the solution code!)

Exercise 4: Solution

              
"use strict";
window.onload = function() {
  document.getElementById("calculate").onclick = convert;
}

function convert() {
  let input = document.getElementById("input");
  value = parseInt(input.value);
            
  let conversion = document.getElementById("convert");
  if (conversion.value == "kgtopounds") {
    value *= 2.20462262;
  } else {
    value *= 0.45359237;
  }
                                       
  let answer = document.getElementById("answer");
  answer.innerHTML = value;
}
             
           

Exercise 5: Adopt a Llama Today!

This was inspired by a past quarter's Creative Project!

Note: We haven't covered enough to go over this yet, but feel free to explore different HTML tags and JS handlers if you want an additional challenge! We'll know enough by Thursday to also solve this one :)

Write a JavaScript file llamas.js to be used with the given adopt-a-llama.html file so that when the Validate button is clicked, every input in the form including the textarea that has a blank value (empty string) will be highlighted with a "red" background color, as shown in the screenshots below.

If a text box already has the red background but is then changed to non-blank, and the Validate button is clicked again, then you should remove the red background color by setting the background to an empty string, "". You should not modify HTML or CSS code; write only JavaScript. Use the document.querySelectorAll function (covered in later lecture).

Exercise 5: Example Appearance and Behavior

Before clicking verify button:

before image

After clicking verify button:

after image

Exercise 5: Solution


"use strict";
window.onload = function() {
  document.getElementById("validate").onclick = checkInputs;
};

function checkInputs() {
  let inputs = document.querySelectorAll("input");
  for (let i = 0; i < inputs.length; i++) {
    if (inputs[i].value < 1) {
      inputs[i].style.backgroundColor = "red";
    } else {
      inputs[i].style.backgroundColor = "white";
    }
  }
  let textareaInput = document.querySelectorAll("textarea")[0];
  if (textareaInput.value < 1) {
    textareaInput.style.backgroundColor = "red";
  } else {
    textareaInput.style.backgroundColor = "white";
  }
}
            

JS