Most JavaScript does not run automatically. JavaScript was created to allow people to interact with webpages and so far, none of my examples have been interactive. To allow interaction with a webpage, JavaScript is triggered through a group of commands known as events. Most events are mouse movements, but some are tied to the keyboard as well. These are pretty much the most important part of JavaScript.
Events operate by running code when the event occurs.
The events are:
These may be tied to an element in two ways: 1) as an element node property in JavaScript or 2) as an attribute in the start tag itself. In (X)HTML, the event attributes are almost as ubiquitous as the core and language attributes; in fact I got the above list from the HTML 4.01 DTD itself. You can see the section on event attributes at http://www.w3.org/TR/html401/sgml/dtd.html#events.
These attributes may not be used with the following:
With the sole exception of bdo
, none of these elements give you anything to click on anyways.
The body
element has all of the above events plus two more associated with it:
I normally avoid using event attributes for a number of reasons.
The fourth reason—actually programming the event— I will explain shortly.
In JavaScript Objects, you'll remember that we could assign methods to properties (I even demonstrated how to assign a method directly without giving it a name). We do the same thing with events: the procedures we create and assign to events become methods of that particular element node object.
Before we assign an event, let's set up a procedure for that event to work with. This procedure will decide whether or not the value we send to it is greater than, less than, or equal to 5, or if it's a number at all.
function
Write
(num){var
text = "The value is "
;if
(isNaN
(num)){"not a number."
;else
{if
(num < 5){"less than "
;else
if
(num > 5){"greater than "
;else
{"equal to "
;"5."
;document
.getElementById
("Answer"
).firstChild
.data
= text;I've also created a page to use this:
The blue square is a div
element to which I've assigned four different events. Using events as attributes, the code for this element looks like this:
As you can see, the values of the event attributes are all procedure calls. However, it's almost as easy to assign them through JavaScript. To select which element to assign these, we use the method getElementById
to get the div
element with unique identity Events
; we may as well use that ID for scripting, since we're already using that ID for styling purposes:
Now let's use it for scripting as well:
var
events = document
.getElementById
("Events"
);onmouseover
= function
(){Write
("Something else"
);}onclick
= function
(){Write
(4);}ondblclick
= function
(){Write
(6);}onmouseout
= function
(){Write
(5);}You can see that this gets more complicated when I assign them through JavaScript. When I used the attributes, I didn't have the word function
in there, nor the extra braces, so why don't I have something like events.
? Feel free to try that, but I'll tell you right now that this will make that procedure run automatically; you're calling the procedure by assigning it.onmouseover
= Write
("Something else"
);
As I said earlier, what we are doing here is making these mouse events methods. These methods contain calls to the functions we wish to use, so the function call will not be triggered until the method assigned to the mouse event is triggered. Sounds complicated, I know, but that's the best I can describe it.
Below are the results of the script. The text Write
returns appears at the top of the page in each screenshot, right beside JavaScript Result:
.
onmouseover
): Write
("Something else"
);
onmouseover
sends the value Something Else
to Write
. AS the string cannot be converted into a number, the result is The value is not a number.
onclick
): Write
(4);
onclick
sends the value 4
to Write
, and the returned text is The value is less than 5.
ondblclick
): Write
(6);
ondblclick
sends the value 6
to Write
, and the returned text is The value is more than 5.
onmouseout
): Write
(5);
onmouseout
sends the value 5
to Write
, and the returned text is The value is equal to 5.
It is really that straightforward. You can have as much code as you please in the assigned click event. You could even get rid of Write
and assign its code to each event:
Write
Functionvar
events = document
.getElementById
("Events"
);var
text = "The value is "
;var
num;onmouseover
= function
(){"Something else"
;if
(isNaN
(num)){"not a number."
;else
{if
(num < 5){"less than "
;else
if
(num > 5){"greater than "
;else
{"equal to "
;"5."
;document
.getElementById
("Answer"
).firstChild
.data
= text;onclick
= function
(){if
(isNaN
(num)){"not a number."
;else
{if
(num < 5){"less than "
;else
if
(num > 5){"greater than "
;else
{"equal to "
;"5."
;document
.getElementById
("Answer"
).firstChild
.data
= text;ondblclick
= function
(){if
(isNaN
(num)){"not a number."
;else
{if
(num < 5){"less than "
;else
if
(num > 5){"greater than "
;else
{"equal to "
;"5."
;document
.getElementById
("Answer"
).firstChild
.data
= text;onmouseout
= function
(){if
(isNaN
(num)){"not a number."
;else
{if
(num < 5){"less than "
;else
if
(num > 5){"greater than "
;else
{"equal to "
;"5."
;document
.getElementById
("Answer"
).firstChild
.data
= text;The above neatly demonstrates two things:
onmouseover
had some string-based operations unique to that event, the Write
function would be useless, and I could assign coding directly to the onmouseover
event. Because of the very nature of JavaScript programming, doing that the onmouseover
attribute would be either very difficult or downright impossible.The function Write
is remaining exactly the same, but the code that assigns events is changing. This time, I'm assigning click events to the following list of buttons:
I could assign click events one by one to these buttons:
var
buttons = document
.getElementById
("Buttons"
).getElementsByTagName
("button"
);onclick
= function
(){Write
("Something else"
);}onclick
= function
(){Write
(4);}onclick
= function
(){Write
(6);}onclick
= function
(){Write
(5);}But this gets to be a pain in the butt, especially if I'm using something like this on multple pages with different numbers of buttons. So either I'll need a drink to cure such a headache, or I need a loop.
Actually, why choose between the two? Excuse me.
The first adjustment to the above code is to have it get the information from the button text for each button:
var
buttons = document
.getElementById
("Buttons"
).getElementsByTagName
("button"
);onclick
= function
(){buttons[0].firstChild
.data
}onclick
= function
(){buttons[1].firstChild
.data
}onclick
= function
(){buttons[2].firstChild
.data
}onclick
= function
(){buttons[3].firstChild
.data
}Now we are ready for a loop. The loop we will use is a for loop, since buttons is a node list.
var
buttons = document
.getElementById
("Buttons"
).getElementsByTagName
("button"
);for
(var
l = 0; l < buttons.length
; l++){When you use a loop, you can't simply assign a method as we've done earlier. It's a bit more complicated than that. You have to assign a new method for every iteration of the loop. You accomplish that by returning
a method containing a call to the function you ultimately want to trigger. In other words,
will only work for a single assignment, but it in a loop, and you will get errors. Instead, you have to use this: function
(){Write()
}
Furthermore, you have to specify which iteration for each method returned. See the function
(){return
function
(){ Write()
)}()
after the first function
keyword? That's where the variable containing that value goes. You also have to use that variable at the end of the assignment as well, again in parentheses:
. Don't ask me why that is; I only know that it doesn't work any other way. Below is the complete code:function
(l){return
function
(){ Write()
)}(l);
onclick
Events Assigned Through A Loopvar
buttons = document
.getElementById
("Buttons"
).getElementsByTagName
("button"
);for
(var
l = 0; l < buttons.length
; l++){onclick
= function
(l){return
function
(){buttons[l].firstChild
.data
}}(l);Below are five images, the first displaying the page in its original state, the rest showing each button (which is automatically highlighted) being pressed in turn:
Looks complicated, but then again, JavaScript usually is (and other programming languages aren't much better).
This can even be used for nested loops. For example, if I were to assign click events to a table of buttons (I'll give the table the ID of Buttons
), I would do it like this:
var
trs = document
.getElementById
("Buttons"
).getElementsByTagName
("tr"
);var
buttons = new
Array
();for
(var
l = 0; l < trs.length
; l++){getElementsByTagName
("button"
);for
(var
l2 = 0; l2 < buttons.length
; l2++){onclick
= function
(l, l2){return
function
(){buttons[l][l2].firstChild
.data
}}(l, l2);On the first two lines, I create two arrays: a node list of tr
elements named trs, and the array called buttons, which is created as a new array. We'll be assigning values to it shortly.
In the outer loop, I assign a node list of button
elements contained in each tr
element. In the inner loop, I use a loop to assign the click events.
Notice that with nested loops, the actual assignment of an event isn't any more complicated than through a single loop save for the fact that two variables are passed in this case, and in the end pair of parentheses those same variables have to be in the same order that they are in the first pair: (
).function
(l, l2){ . . . }(l, l2);
Below is an example of the resultant page:
And when the user uses this webpage, it all looks so completely normal, no matter how loopy things are behind the scenes.
On occasion, a click event needs a great deal of information from the element that the event is assigned to, or the event groups several elements together. One way to keep this all straight is to assign the click event through an object, which will contain the necessary information.
I assign click events in such a manner in one example page of my book: the page that demonstrates subpatterns in a regex. Because that example uses concepts I haven't explained yet (in particular, concepts explained in Manipulating The DOM), I altered an example shown in Functions And Methods—specifically, P_Full_Text
, used throughout that chapter.
I made it into the object template P_Info
. Each p
element node has its own instance of P_Info
assigned to the property OnClickScript
; assigning element-specific objects to new properties of the element nodes they refer to is something I often do to keep code from tripping over itself.
Below is the object itself:
P_Info
Object Templatefunction
P_Info
(el){var
p_child = el.childNodes
;var
show = "Node_Count"
;var
txt = document
.getElementById
("td_"
+ el.getAttribute
("id"
).substr
(2)).firstChild
;var
p_text = ""
;for
(var
loop = 0; loop < p_child.length
; loop++){nodeType
== 3)?(p_child[loop].data
):(p_child[loop].firstChild
.data
);onclick
= function
(){data
= (show == "Node_Count"
)?p_text:p_child.length
;"Node_Count"
)?"El_Text"
:"Node_Count"
;There is something very important that is you should notice: this
is not here. That is no mistake; I do not need to get any information or use any functions in this object; I just need it to assign a click event to whatever element is passed to the template through el.
P_Info
Object Templatevar
pars = document
.getElementsByTagName
("p"
);var
i = 0; i < pars.length
; i++){OnClickScript
= new
P_Info
(pars[i]);In this case, it's p
elements, which means that the onclick
event in the template is assigned to them.
In the above page, the first paragraph has been clicked on and the second has not, so they display different information.
I have assigned events through objects several times. Certainly, objects came in handy in one very large page that set up a schedule for a fantasy basketball league: each tr
element (which corresponded to a date) was assigned an object, and the inner workings of the object's template assigned onchange
events to select
elements—24 per row!—along with loads of crosschecking within that row to make sure that a game could take place on that date. Doing it without objects would have been difficult at best. That was the same template as the one I mentioned having been used more than 200 times in JavaScript Objects.