The first argument indicates what we’re listening for—we want to run this code whenour form is submitted.. Save, go back to your browser, reload the page, and.. Take the offending line o
Trang 1The first argument indicates what we’re listening for—we want to run this code when
our form is submitted The second argument is our responder—the name of the function
that will get called when the form’s submitevent fires
Add the submitEntryFormfunction and the observecall to breakfast.js Save, go back
to your browser, reload the page, and what? Error? (See Figure 5-3.)
Figure 5-3.Guh?
Of course it’s defined! It’s right there on the page! I’m staring straight at it!
Firebug can tell us what went wrong Select the Script tab, click Options, and then
click Break on All Errors This way you’ll know exactly when that error happens
Reload the page Almost immediately the page load will halt, as Firebug points you
to the offending line (see Figure 5-4)
Figure 5-4.When Break on All Errors is on, any error in your code is treated as a debugger
breakpoint.
Trang 2The Script tab is Firebug’s JavaScript debugger We’ve just set a breakpoint,
paus-ing the evaluation of scripts (and renderpaus-ing in general) at a certain spot From here,
we can resume the page load, step through functions one by one, and even use Fire-bug’s console
But right now we don’t need to do any of that—the screen tells us all we need to know Notice how the viewport is empty None of our content is there At the time we
tried to set the event, the element we were referencing hadn’t yet been created.
This is an easy trap to fall into Script tags are typically placed in the head of an HTML document In the common case where a script needs to modify stuff in the
body of a document, it’s got to wait.
OK, new plan—we’ll add our listeners when the document is fully loaded, so that we
can be sure that the entire DOM tree is at our disposal Take the offending line of code and place it inside a function:
function addObservers() {
$('entry').observe('submit', submitEntryForm);
}
Now we can set this function to run when the page loads using the loadevent: Event.observe(window, 'load', addObservers);
Make these changes to breakfast.js, and then reload the page Our error is gone— and, more to the point, the Ajax form submission works this time! Wait, no Never mind Something else is wrong (see Figure 5-5)
What could be causing this? The only thing on the page is the HTML fragment that
should’ve been injected into our other page.
Look at the address bar When we submitted the form, the browser went to break-fast.php, the URL in the form’sactionattribute Following that URL is the submitevent’s
default action.
That means we’re at fault again When we submitted the form, submitEntryFormwas
called as we intended But we didn’t hijack the submit event; we just listened for it If we
want to suppress this default action, we must explicitly say so
Trang 3Figure 5-5.This is the HTML fragment we wanted, but it’s on its own page.
Using Event#stopPropagation, Event#preventDefault,
and Event#stop
To pull this off, we’re borrowing a couple of methods from the DOM2 Events spec
Internet Explorer doesn’t support these events natively, but we can fake it on the fly—
augmenting Internet Explorer’s event object with instance methods the same way we
augment DOM nodes with instance methods
First, we add an eventargument to our handler so that we can use the event object
(We could have done this from the start, but we didn’t have a use for it until just now.)
Then, at the end of the handler, we tell the event not to do what it had originally planned
function submitEntryForm(event) {
var updater = new Ajax.Updater({
success: 'breakfast_history', failure: 'error_log'
}, 'breakfast.php',
{ parameters: { food_type: $('food_type').value, taste: $('taste').value } });
event.preventDefault();
}
Trang 4Prototype gives you two other methods to control the flow of events:
• Normally, events start deep in the DOM tree and “bubble” up to the top (e.g., click-ing a table cell will also fire an event in that cell’s table row, in the table body, in the table, in the table’s parent node, and so on all the way up to window) But you can halt the bubbling phase using the stopPropagationmethod
• When you need to stop the event from bubbling and prevent the default action,
use Prototype’s custom stopmethod It’s a shortcut for calling both stopPropagation and preventDefault
OK, let’s try one more time Reload index.htmland try to submit a breakfast log (see Figure 5-6)
Figure 5-6.Finally, we can submit meal information without having to reload the page! Eureka!
That was easy, right? Right?
Be aware: The behavior layer of web development (JavaScript) is far more complex than the structural layer (HTML) or the presentational layer (CSS) Ordinary web pages
Trang 5are snapshots—the server sends it, the browser renders it, and it’s done Pages that make
use of JavaScript, however, have some aspect of mutability to them The page may be
loaded, but it’s never done.
You will run into problems like the ones we encountered in this example You will
make mistakes simply because all this may be new and unfamiliar Don’t get
discour-aged! Rely on your tools—Firebug, Microsoft Script Debugger, and even the trusty alert
dialog—to get you out of the quagmire
A Further Example
We’ll keep coming back to events in subsequent chapters, since they’re a part of
every-thing you do in DOM scripting But let’s add just one more every-thing to our page
Being able to post entries without leaving the page is quite handy, but what if you’re
just there to read your old entries? In the interest of removing clutter, let’s hide the form
by default, showing it only if the user asks for it
Let’s assign an idto the Log Your Breakfast heading so that we can grab it easily Let’s
also write some CSS to make it feel more button-like and invite clicking
// HTML:
<h2 id="toggler">Log Your Breakfast ↓</h2>
// CSS:
#toggler {
cursor: pointer;
border: 2px solid #222;
background-color: #eee;
}
We also want the form to be hidden when the page first appears, so let’s add a
handler that will hide the form when the page loads:
Event.observe(window, "load", function() { $('entry').hide(); });
And the last ingredient is a handler for the new link’s clickevent:
function toggleEntryForm(event) {
$('entry').toggle();
event.preventDefault();
}
The togglemethod conveniently alternates an element between hidden and shown
(In other words, it will show hidden elements and hide shown elements.) Note the use of
Trang 6preventDefault—since we don’t want the browser to follow the link, we’ve got to suppress
the default action
We can assign this event just like we assigned the other one—with our addObservers function:
function addObservers() {
$('entry').observe('submit', submitEntryForm);
$('toggler').observe('click', toggleEntryForm);
}
Now two events will be assigned on page load Save breakfast.js, reload index.html, and marvel that this exercise was much easier than the last (see Figure 5-7)
Figure 5-7.Each click of the link will toggle the display state of the form.
Events and Forms
A whole group of events is devoted to the user’s interaction with form elements These can be tricky to manage, but they also stand to gain the most from UI enhancements
Client-Side Validation
In Chapter 4, we wrote some PHP to check the submitted values on the server side If the user had left either field blank, the submission would have been invalid, and the server would have sent back an error HTTP status code