INTRODUCTION TO JQUERY – HANDLING EVENTS - A SIMPLE STYLE SWITCHER

JavaScript has several built-in ways of reacting to user interaction and other events. To make a page dynamic and responsive, we need to harness this capability so that we can, at the appropriate times, use the jQuery techniques.

jQuery enhances and extends the basic event handling mechanisms available with basic JavaScript to give them a more elegant syntax, while at the same time making them more powerful.

Timing of code execution

$(document).ready() is jQuery's primary way to perform tasks on page load. It is not, however, the only method at our disposal. The native window.onload event can achieve a similar effect. While the two methods are similar, it is important to recognize their difference in timing, even though it can be quite subtle depending on the number of resources being loaded.

The window.onload event fires when a document is completely downloaded to the browser. This means that every element on the page is ready to be manipulated by JavaScript.

On the other hand, a handler registered using $(document).ready() is invoked when the DOM is completely ready for use. This also means that all elements are accessible by our scripts, but does not mean that every associated file has been downloaded. As soon as the HTML has been downloaded and parsed into a DOM tree, the code can run.

Style loading and code execution

To ensure that the page has also been styled before the JavaScript code executes, it is a good practice to place <link rel="stylesheet"> and <style> tags prior to <script> tags within the document's <head> element.

Consider, for example, a page that presents an image gallery. Such a page may have many large images on it, which we can hide, show, move, and otherwise manipulate with jQuery. If we set up our interface using the onload event, users will have to wait until each and every image is completely downloaded before they can use those features. Even worse, if behaviours are not yet attached to elements that have default behaviours (such as links), user interactions could produce unintended outcomes.

However, when we use $(document).ready() for the setup, the interface is ready to use earlier with the correct behaviour.

What is loaded and what is not?

Using $(document).ready() is almost always preferable to using an onload handler, but we need to keep in mind that because supporting files may not have loaded, attributes such as image height and width are not necessarily available at this time. If these are needed, we may, at times, also choose to implement an onload handler (or more likely, use jQuery to bind a handler to the load event); the two mechanisms can coexist peacefully.

JavaScript has several built-in ways of reacting to user interaction and other events. To make a page dynamic and responsive, we need to harness this capability so that we can, at the appropriate times, use the jQuery techniques.

Multiple scripts on one page

The traditional mechanism for registering event handlers through JavaScript (rather than adding handler attributes right in HTML) is to assign a function to the DOM element's corresponding attribute. For example, suppose we had defined the function:

function doStuff() {

// Perform a task...

}

We could then either assign it within our HTML markup:

<body onload="doStuff();">

Or, we could assign it from within JavaScript code:

window.onload = doStuff;

Both of these approaches will cause the function to execute when the page is loaded.

The advantage of the second is that the behaviour is more cleanly separated from the markup.

Referencing vs. calling functions

Note here, that when we assign a function as a handler, we use the function name but omit the trailing parentheses. With the parentheses, the function is called immediately. Without the parenthesis, the name simply identifies, or references the function, and can be used to call it later.

With one function, this strategy works quite well. However, suppose we have a second function:

function doOtherStuff() {

// Perform another task...

}

We could then attempt to assign this function to run on page load:

window.onload = doOtherStuff;

However, this assignment trumps the first one. The .onload attribute can only store one function reference at a time. Therefore, we can't add this to the existing behaviour.

The $(document).ready() mechanism handles this situation gracefully. Each call to the method adds the new function to an internal queue of behaviours. When the page is loaded all of the functions will execute. The functions will run in the order in which they were registered.

Shortcuts for code brevity

The $(document).ready() construct is actually calling the .ready() method on a jQuery object we've constructed from the document DOM element. The $() function provides a shortcut for us as this is a common task. When we pass in a function as the argument, jQuery performs an implicit call to .ready(). For the same result as shown in the following code snippet:

$(document).ready(function() {

// Our code here...

});

We can also write the following code:

$(function() {

// Our code here...

});

While this other syntax is shorter, the longer version makes code more descriptive about what it is doing.

Passing an argument to the .ready() callback

In some cases, it may prove useful to use more than one JavaScript library on the same page. As many libraries make use of the $ identifier (as it is short and convenient), we need a way to prevent collisions between these uses.

Fortunately, jQuery provides a method called jQuery.noConflict() to return control of the $ identifier back to other libraries. Typical usage of jQuery.noConflict() is as follows:

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

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

<script>

jQuery.noConflict();

</script>

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

First, the other library (Prototype in this example) is included. Then, jQuery itself is included, taking over $ for its own use. Next, a call to .noConflict() frees up $, so that control of it reverts to the first included library (Prototype). Now in our custom script, we can use both libraries - but whenever we want to use a jQuery method, we need to write jQuery instead of $ as an identifier.

The .ready() method has one more trick up its sleeve to help us in this situation.

The callback function we pass to it can take a single parameter - the jQuery object itself. This allows us to effectively rename it without fear of conflicts, as shown in the following code snippet:

jQuery(document).ready(function($) {

// In here, we can use $ like normal!

});

Or, using the shorter syntax we learned in the preceding code:

jQuery(function($) {

// Code that uses $.

});

Simple events

There are many other times, apart from the loading of the page, at which we might want to perform a task. Just as JavaScript allows us to intercept the page load event with <body onload=""> or window.onload, it provides similar hooks for user-initiated events such as mouse clicks (onclick), form fields being modified (onchange), and windows changing size (onresize). When assigned directly to elements in the DOM, these hooks have similar drawbacks to the ones we outlined for onload. Therefore, jQuery offers an improved way of handling these events as well.

To illustrate some event handling techniques, suppose we wish to have a single page rendered in several different styles based on user input. We will allow the user to click buttons to toggle between a normal view, a view in which the text is constrained to a narrow column, and a view with large print for the content area.

1.  Create a new folder in your MySites folder called Style Switcher.

2.  Locate the folder on the K:\ drive under K:\Sue Brandreth called Style Switcher Files and copy its contents into your Style Switcher folder.

3.  Define a new Dreamweaver site called Style Switcher and set the root folder as the Style Switcher folder that you have just created.

4.  Open the web page index.html and view the code.

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>A Christmas Carol</title>

<link rel="stylesheet" href="03.css" type="text/css" />

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

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

</head>

<body>

<div id="container">

<div id="switcher" class="switcher">

<h3>Style Switcher</h3>

<button id="switcher-default">

Default

</button>

<button id="switcher-narrow">

Narrow Column

</button>

<button id="switcher-large">

Large Print

</button>

</div>

<div id="header">

<h2>A Christmas Carol</h2>

<h2 class="subtitle">In Prose, Being a Ghost Story of Christmas</h2>

<div class="author">by Charles Dickens</div>

</div>

<div class="chapter" id="chapter-preface">

<h3 class="chapter-title">Preface</h3>

<p>I HAVE endeavoured in this Ghostly little book, to raise the Ghost of an Idea, which shall not put my readers out of humour with themselves, with each other, with the season, or with me. May it haunt their houses pleasantly, and no one wish to lay it.</p>

<p>Their faithful Friend and Servant,</p>

<p>C. D.</p>

<p>December, 1843.</p>

</div>

<div class="chapter" id="chapter-1">

<h3 class="chapter-title">Stave I: Marley's Ghost</h3>

<p>MARLEY was dead: to begin with. There is no doubt whatever about that. The register of his burial was signed by the clergyman, the clerk, the undertaker, and the chief mourner. Scrooge signed it: and Scrooge's name was good upon 'Change, for anything he chose to put his hand to. Old Marley was as dead as a door-nail.</p>

<p>Mind! I don't mean to say that I know, of my own knowledge, what there is particularly dead about a door-nail. I might have been inclined, myself, to regard a coffin-nail as the deadest piece of ironmongery in the trade. But the wisdom of our ancestors is in the simile; and my unhallowed hands shall not disturb it, or the Country's done for. You will therefore permit me to repeat, emphatically, that Marley was as dead as a door-nail.</p>

<p>Scrooge knew he was dead? Of course he did. How could it be otherwise? Scrooge and he were partners for I don't know how many years. Scrooge was his sole executor, his sole administrator, his sole assign, his sole residuary legatee, his sole friend, and sole mourner. And even Scrooge was not so dreadfully cut up by the sad event, but that he was an excellent man of business on the very day of the funeral, and solemnised it with an undoubted bargain.</p>

<p>The mention of Marley's funeral brings me back to the point I started from. There is no doubt that Marley was dead. This must be distinctly understood, or nothing wonderful can come of the story I am going to relate. If we were not perfectly convinced that Hamlet's Father died before the play began, there would be nothing more remarkable in his taking a stroll at night, in an easterly wind, upon his own ramparts, than there would be in any other middle-aged gentleman rashly turning out after dark in a breezy spot&mdash;say Saint Paul's Churchyard for instance&mdash; literally to astonish his son's weak mind.</p>

<p>Scrooge never painted out Old Marley's name. There it stood, years afterwards, above the warehouse door: Scrooge and Marley. The firm was known as Scrooge and Marley. Sometimes people new to the business called Scrooge Scrooge, and sometimes Marley, but he answered to both names. It was all the same to him.</p>

<p>Oh! But he was a tight-fisted hand at the grind-stone, Scrooge! a squeezing, wrenching, grasping, scraping, clutching, covetous, old sinner! Hard and sharp as flint, from which no steel had ever struck out generous fire; secret, and self-contained, and solitary as an oyster. The cold within him froze his old features, nipped his pointed nose, shrivelled his cheek, stiffened his gait; made his eyes red, his thin lips blue; and spoke out shrewdly in his grating voice. A frosty rime was on his head, and on his eyebrows, and his wiry chin. He carried his own low temperature always about with him; he iced his office in the dog-days; and didn't thaw it one degree at Christmas.</p>

<p>External heat and cold had little influence on Scrooge. No warmth could warm, no wintry weather chill him. No wind that blew was bitterer than he, no falling snow was more intent upon its purpose, no pelting rain less open to entreaty. Foul weather didn't know where to have him. The heaviest rain, and snow, and hail, and sleet, could boast of the advantage over him in only one respect. They often "came down" handsomely, and Scrooge never did.</p>

<p>Nobody ever stopped him in the street to say, with gladsome looks, "My dear Scrooge, how are you? When will you come to see me?" No beggars implored him to bestow a trifle, no children asked him what it was o'clock, no man or woman ever once in all his life inquired the way to such and such a place, of Scrooge. Even the blind men's dogs appeared to know him; and when they saw him coming on, would tug their owners into doorways and up courts; and then would wag their tails as though they said, "No eye at all is better than an evil eye, dark master!"</p>

<p>But what did Scrooge care! It was the very thing he liked. To edge his way along the crowded paths of life, warning all human sympathy to keep its distance, was what the knowing ones call "nuts" to Scrooge.</p>

</div>

</div>

</body>

</html>

Note the HTML code for the style switcher (highlighted above).

5.  View index.html in a browser. The page when combined with some basic CSS should appear as shown below:

6.  The line of code:

<link rel="stylesheet" href="03.css" type="text/css" />

refers to the CSS file 03.css. Open 03.css and view the code:

/*Default styles*/

html, body {

margin: 0;

padding: 0;

}

body {

font: 62.5% Verdana, Helvetica, Arial, sans-serif;

color: #000;

background: #fff;

}

#container {

font-size: 1.2em;

margin: 10px 2em;

}

h1 {

font-size: 2.5em;

margin-bottom: 0;

}

h2 {

font-size: 1.3em;

margin-bottom: .5em;

}

h3 {

font-size: 1.1em;