Introduction to JavaScript Fall 2010 Class 4

esse quam videri
Revision as of 22:49, 28 September 2010 by Matthew.ephraim (talk | contribs)
Jump to: navigation, search

Back to Introduction to JavaScript Fall 2010

Introduction

Last week, I showed you how you can wrap chunks of JavaScript code up into functions that can be reused throughout your page. This week, I will explain JavaScript events and show you how you can tie JavaScript functions to different user events that happen on your page.

I will also show you how you can change an element's HTML and even change an element's styles.

Coding Style

One thing that I haven't talked about yet is coding style. Like the English language, JavaScript has it's own styles that you should follow if you want to make your code readable for others (and, of course, for yourself).

The Mozilla JavaScript Style Guide is a comprehensive list of rules that you should try to follow when writing JavaScript. Some of the rules are more important than others, and many of them might not make sense yet for a beginner class. I've listed a few of the rules that apply for this class so far.

Variables and Functions

Clear Naming

Your variables and functions should have names that clearly indicate what the variable is being used for or what the function does. For example, the following variable is being used to store a person's name:

  var n = "Matthew Ephraim";

This is a bad variable name, because n doesn't tell you anything about what the variable is used for, so it might be confusing later on. A much better name would look like this:

  var name = "Matthew Ephraim";

This name is better because name tells you what the variable is being used for.

Multiple Word Names

When your variable or function names have multiple words in them, it's JavaScript style to use camel case (aka camelCase) to indicate that the variable names are multiple words. For example, this variable name is made up of 2 words:

  var professorname = "Matthew Ephraim";

It's 2 words, but it's also difficult to read. It can be made clearer by using camel case:

  var professorName = "Matthew Ephraim";

Notice that the N is capitalized now. This makes it easier to see where the 2 words are separated. Variables names can't have spaces in them, so this is a simple way to still use 2 words in the variable name. Longer variables names with multiple words can be used as well:

  var professorFullName = "Matthew Ephraim"; // professor full name, 3 words
  var firstClassStartTime = "6:30pm"; // first class start time, 4 words

Indentation

Another important coding style is using proper indentation in your code. Just like indenting the first sentence of a paragraph can make text easier to read, indenting your code properly can make it easier to read as well. Typically, when you switch to a new block of code, you should indent 2 spaces.

Remember that, in JavaScript, bocks are sections of code that are surrounded by { curly brackets }. So, every time you're using an opening curly bracket, you should indent 2 spaces. The code example below doesn't use any indentation:

  function alertMatt() {
  if (name === "Matt") {
  alert('hello Matt');
  } else {
  alert('You're not Matt!');
  }
  }

Is this code easy to read? How about if it was indented:

  function alertMatt() {
    if (name === "Matt") {
      alert('hello Matt');
    } else {
      alert('You're not Matt!');
    }
  }

Is this code easier to read? The code that goes with the function is indented several spaces, and the code that's associated with the if statement and with the else statement is also indented several spaces more. Most good text editors should have a feature that help you properly indent your code.

Coding Style Links

Finding Elements

Before we can start capturing events and writing our own code to handle those events, we need to be able to find the elements that we want to attach event handlers to. Let's say you have a div on the page and you give it an id of clickableDiv:

  <div id="clickableDiv"></div>

If you wanted to find the div and store it in a variable, you would use the document.getElementById function:

  var clickableDiv = document.getElementById('clickableDiv');

If the div was found, the function returns the element. Later on, you can use the clickableDiv variable to attach events to the element.

Events

In JavaScript, events are raised when a user takes some action on the page. For example, a user clicking on link would raise the onclick event on the element that the user clicked on. Without JavaScript, the user interacts with the page and the browser handles any events that the user might raise. Many times, the browser's way of handling the events is just fine. Other times, there may be more interesting things that we can do with JavaScript by capturing the events and handling them in a different way than the browser would handle the events.

What kind of actions from the user are considered events though? It depends on the browser, but, for the most part there is a core set of events that the majority of browsers will support. So, for example, a user might click on an element on the page. If the element is a button, the browser will submit a form. If the element is an anchor, the browser will go to the page that the anchor links to. Or maybe the user just clicked on a div element. In that case, the browser probably wouldn't do anything. Not unless we add some JavaScript.

Setting Events

So, let's take the div from above:

   var clickableDiv = document.getElementById('clickableDiv');

We now have the div stored in a variable called clickableDiv. Let's say we wanted to have a function that handled the event that was raised when the user clicked on clickableDiv. First, we should create a function that will be used to handle the event. Let's call it handleClick.

  function handleClick() {
      console.log('hello');
  }

The function will write message that says "hello" to the Firebug console when it is called. Let's make it so that the function is called when the user clicks on clickableDiv. To do this, we'll need to use the clickableDiv variable that we the element by adding a dot (.) after the variable name and then the name of the attribute. In this case, we want to modify the onclick attribute of the element, and set it to the name of the new function that we created:

  clickableDiv.onclick = handleClick;

Notice that we used the clickableDiv variable and we added .onclick after it and then set it equal to handleClick. Attributes of elements work like variables, we can set them with the equals sign and even use them for comparisons later on.

Other Events

We already set the onclick event, but there are other events that we could have set as well. For example, if we wanted to call a function when the user pressed their mouse button down we could add a handler for the onmousedown function. When the user released the mouse button, we could capture the onmouseup function:

  clickableDiv.onmousedown = handleMouseDown;
  clickableDiv.onmouseup = handleMouseUp;

Or maybe we want to capture the event that happens when the user moves their mouse over an element (onmouseover) or maybe when a user doubleclicks (ondblclick) their mouse:

 clickableDiv.onmouseover = handleMouseOver;
 clickableDiv.ondblclick = handleDoubleClick;

There are some events that apply to all elements on the page and other events (like onchange) that apply specifically to HTML form elements. For a comprehensive list of events and which browsers support each of them, see here.

the window.onload Event

One issue that you will run into when attaching events with JavaScript is that the code to attach your events often runs before the whole page has actually loaded. This can happen if you include your JavaScript in the head tag of your page. The browser will load the JavaScript as soon as it encounters your script tag, but the rest of the page stil needs to load before you can start attaching events to elements.

A common solution to this problem is to attach an event to the window's onload event. Every page has a window object that represents the current browser window. When the page loads, the browser will raise the window's onload event, which you can attach a handler function to.

So, let's say you want to run a function called setup when the page loads. You can attach the setup function to onload event like this:

 function setup() {
   // do some setup stuff
 }
 
 window.onload = setup;

Any JavaScript that gets called in the setup function will be called after the page has loaded. So, you should have access to all of the elements on the page.

this Keyword

There is a special keyword in JavaScript that I haven't mentioned yet, and you can start taking advantage of it now that you've starting to use events. JavaScript has a special keyword called this that behaves in different ways, depending on where you use it. It's often confusing, but when used with events, it's fairly straightforward. Let's say that we used the following code to set an onclick handler for an element:

 clickableDiv.onclick = handleClick;
 
 function handleClick() {
   alert(this);
 }
 

The code looks fairly simple: it adds handleClick as an onclick handler for clickableDiv. handleClick gets called when the user clicks on the div and the fuction alerts the user. But what does the user see when they get alerted? If you tried to run this code, you would probably see something like the text below when you click on the div:

  object HTMLDivElement

The message you are getting from the browser is telling you that this is pointing to a div element on the page. But which div element? It's the same one that clickableDiv points to and the same element that you clicked on. In other words, this is a special keyword that points to the element that has the event handler attached to it.

The this keyword can come in handy because it will always give you a reference to the element that raised an event. It's like having a variable that automatically gets created for the element. That way, you don't need to use document.getElementById because this already gives you a reference to the element.

JavaScript Event Links

In addition to the wiki, you may find these links helpful

Modifying Elements

Handling events isn't the only thing you can do with elements on your page. Once you've found an element on the page you can modify the element in many different ways. Two of the simplest things you can do to an element is change the HTML inside of an element and change the styles applied to an element.

Changing the HTML

Once again, we'll use the clickableDiv variable from above. Let's say that we wanted to change the content inside of clickableDiv to say "hello" when the div was clicked on. To do this, we would need to change the innerHTML of clickableDiv. Nearly all elements have an innerHTML attribute that references the HTML inside of the element. We can use innerHTML to see the content inside of the element or we can set innerHTML to a new value to change the content inside of the element to something new.

We can create a new handler that uses the innerHTML attribute of clickableDiv to modify the content:

  clickableDiv.onclick = handleClick;
 
  function handleClick() {
    clickableDiv.innerHTML = "hello";
  }

Setting the innerHTML attribute of clickableDiv changes the content to say "hello". Notice that we used the clickableDiv variable to make these changes. There's another way that we could get access to the element that clickableDiv is pointing to. Remember the this keyword from above? This version of the handleClick will do the same thing as the one above, but it uses the this to reference the element instead:

  clickableDiv.onclick = handleClick;
 
  function handleClick() {
    this.innerHTML = "hello";
  }

Whenever possible, use this to reference the element that raised the event from the user.

Changing the Styles

Changing Styles Directly

An element's HTML isn't the only thing that you can change with JavaScript. You can also change an element's styles as well. For example, we might want clickableDiv to have a green border when a user puts their mouse over the div. We might also want any text inside of it to turn green. We could add a onmouseover handler that captures the event when a user puts their mouse over an element. The handler could use the the element's style attribute to gain access to the element's css styles and then modify the element's border and font color:

  clickableDiv.onmouseover = handleOver;
 
  function handlerOver() {
       this.style.border = "1px solid green";
       this.style.color = "green";
  }

Every element has a collection of styles that are stored under the style attribute. Most of these styles have the same name as their matching css styles. So, any style that you could set with CSS you can also set with JavaScript by using the style attribute. When you modify an element's style, the browser will immediately display your changes.

Changing the Class Name

Above, we changed 2 styles on the element. More complex actions might involve a lot more typing and possible a lot more repetition. How might we have handled the styles above by using CSS? We probably would have created a class that wrapped up all of the styles:

   .highlighted {
       border: 1px solid green;
       color: green;
   }

The stylesheet is where styles belong, so it makes the most sense to put the styles there. Once we have the styles, we can take advantage of them in our JavaScript. Just like every element has style attribute with a collection of styles stored under it, every HTML element has a className attribute that can be set by JavaScript. So, instead of setting the CSS styles manually, the onmouseover handler from above can use className attribute to set a new class on the element:

  function handlerOver() {
       this.className = "highlighted";
  }

Changing the style of the element in this way keeps the styles for the page separated from the behavior and keeps your JavaScript much more compact.

Today's Interesting JavaScript Site

Turn any page into asteroids

This piece of JavaScript uses some JavaScript trickery to turn any webpage into a game of asteroids. Using a JavaScript snippet called a bookmarket to allow you to bookmark a piece of JavaScript and reuse it on any site.

Activity

In this activity we will create a 3 number combination lock. We will use a variable to store the combination that opens the lock. We will then use HTML, CSS and JavaScript to build an interface that represents the numbers for the lock and the latch for the lock.

A user should be able to enter the combination and open the lock. If the user hasn't entered the combination correctly yet, the lock shouldn't open. Once the lock has been opened, the user should be able to close it again and have the combination numbers get reset.

Step 1

Download the template for the lock here. I have already created a simple template for the lock numbers and the lock. Unzip the template and place the whole folder of documents on your desktop. Make sure that all of the documents are in the same folders that they were in when they were inside of the zip file. We will start by editing the behavior.js file inside of the JavaScript folder.

Step 2

I've given a function called setup to start with. The first thing you need to do is add a line of code that will make the function run as soon as the page loads.

If you've done it correctly, you should see an alert that says "hi" when you reload the page.

Step 3

Notice that there is a list of variables at the top of file. There are 4 variables that will be used to hold on to the elements on the page. Modify the setup function so that instead of alerting the user it uses the id attribute to find the each of the elements for numbers and the element for the lock. The function should store the elements in the variables that were created at the top of the page. Make sure that you find the elements inside of the setup function though. The JavaScript won't be able to find the elements until the page has loaded

Step 4

Now that we've found the number elements, we need to find add some functionality so that the numbers do something when a user clicks on them. We will eventually make the numbers change when the user clicks on them, but, first, let's just make a function that handles the clicks and tie the function to the elements.

Call the function changeNumber because it will eventually change the number inside of the box. Then use the onclick event handler to tie the function to each of the 3 box elements. Remember that setting onclick equal to a function will make it so that the function gets called when the user clicks the element.

You can test to make sure that your changeNumber function is getting called correctly by putting a call to alert inside of it. If you've set everything correctly you should see an alert when you click on one of the boxes.

Step 5

The next thing we need to do is make the numbers count up when the user clicks on the boxes. The first number in each box is 0. We will need to find this number and add 1 to it.

First, let's see if we can find the current number. Remember that you can access the HTML of an element by using the innerHTML attribute of the element. We used the same onclick handler for all of the elements though. How do we know which element to find the HTML for when a user's clicks a box? See if you can modify changeNumber function so that it alerts the number inside of the box that was clicked. Hint: remember how you can use the this keyword to find the element that raised the event.

Step 6

Now that you know how to get the number from the box you can change the function so that it adds 1 to the number and resets the HTML for the element to the new number.

The first thing you'll want to do is store the number in a variable called currentNumber. Then, once you have the number you can add 1 to it. Do you remember a shorthand we used last week to add 1 to a number?

Once you've added 1 to the number, you need to set the HTML of the element so that it matches the new number. Use the innerHTML attribute again. This time use it to set the value of the new HTML. If things are working correctly the number inside of each box should go up by 1 when you click the box.

Step 7

You'll probably notice one problem with the way the numbers work right now: when you click the numbers, they just keep counting up. What we really want is for the boxes to count up to 9 and then go back to zero if the user clicks again.

Modify the changeNumber function so that it checks if the current number is less than 9 and adds 1 to it if it is. Otherwise, the function should set the number back to 0. Now, when you click on the numbers they should count up to 9 and then go back to 0.

Step 8

The numbers for the combination lock are now working correctly. The next step is to allow user to click the lock image. Add a new function called checkLock that will eventually be used to check if the lock should open. Go back to the setup function and add an onclick handler to the lock so that the checkLock function gets called when user clicks on the lock.

Again, you can check to make sure that you function works by adding an alert to the function.

Step 9

Now we need to check to make sure the user has correctly entered the combination for the lock and then do something if they have. The user's combination will be made up of the HTML that is currently inside of each of the elements. You can store the HTML for all 3 of the box elements in an variable like this:

  var combination = box1.innerHTML + box2.innerHTML + box3.innerHTML;

The combination variable should now be a string equal to the HTML for all 3 box elements. So, if the boxes are all set to 3, combination will be "333".

Write some code that checks if combination is equal to the COMBINATION variable that represents the actual combination for the lock. Alert the user if the combinations are equal to each other.

Step 10

Instead of alerting the user when the combination is correct, we want to change the lock image to one that represents an unlocked lock. When you have an image element, you can change the source for the image by modifying the src attribute. The checkLock function handles onclick for the lock image, which means that checkLock should have access to the lock image through the this keyword. Use this to change the src for the image to "images/unlocked.png" when the user clicks the lock and the combination is correct.

Step 11

We now have a lock that opens, but there is no way to close the lock once it has been opened. It would be nice if we had the ability to lock the lock again.

One thing that we should keep track of is whether or not the lock has been unlocked. Add variable to the top of the page called unlocked and make sure the variable is set to false to start with:

  var unlocked = false;

In the checkLock function set this new variable equal to true at the same time that you change the lock image. Now we have a way of keeping track of if the lock is still locked or not.

Step 12

Now that we can check if the lock is locked or not, we can close the lock and reset the combination if the user clicks on a lock that has already been opened. To do this, we need to modify the checkLock function so that it first checks if the lock has already been unclocked. If it's already been unlocked it should alert the user and say "already unlocked!". Otherwise, it should do what it did before and unlock the lock.

Step 13

Finally, let's write a function that resets the lock back to locked and sets all the numbers back to 0. Call the new function reset. This new function should modify the innerHTML for box1, box2, and box3, so that they are all equal to 0 again. It should also modify the src on the lock element so that it's equal to "images/locked.png" again. And finally, it should set the unclocked variable back to false again.

In the checkLock function you should call the reset function if the lock has already been unlocked.