Sunday, September 15, 2024

Advanced JavaScript Event Handling

written by Jon Perry

As an example for the basic ideas involved in this article, let us re-consider the bus problem I mentioned in the first piece. We may have designed our bus program to travel to the next destination when all the passengers are aboard and have paid. But what happens at the last stop on the bus’s route?

Automatic event handling would immediately take us to the next stop on the list, probably the first stop in the list of stops. But we need greater control over the actual event. We want to ask if the bus is at the last stop on its route, and if it is, we need to stop it. This is advanced event handling.

This looks simple on the surface – but what if passengers get on at the last stop? And pay? What if people are still on the bus? Good programming would find answers to all of these problems.

Some problems do have solutions without advanced event handling, but if we are able to use advanced event handling, we will find that simple and practical solutions to these sort of problems are readily available.

Advanced Event Handling consists of three sections:

  •     Cancelling Events
  •     Event Bubbling
  •     Mouse Capture

Cancelling Events stops them from happening. So, if you press a key, it cancels your onkeypress event.

Event Bubbling is slightly more involved, and uses the hierarchical nature of a web document. Elements have owners, or parents. An image on a document is owned by the document. This means that an event on the image creates an event for the document, and so on.

Mouse Capture is when we transfer all the events for a document to a single element, giving that element the capture.

We will look at all of these concepts in more detail in this article, beginning with Cancelling Events

Cancelling Events

Cancelling Events allows us to prevent the event from being handled by the computer’s inbuilt event handlers.

For example, when an onsubmit event is fired by, for example, someone pressing a submit button on a form, the CPU will receive the event and the computer will then begin the submission process.

This is the automated aspect of event handling that we wish to exercise greater control over. In the above situation, there may be a JavaScript routine that validates the form for required fields. If the form fails the validation testing, we do not want to send the form.

If the form is OK, we leave the event alone. The computer then receives a (submit button, onclick) pair, which automatically triggers the inbuilt mechanism for the form submission process (gather the data, roll into data packet and send to HREF address).

We can achieve this fine degree of control over the event with event cancelling.

The life span of normal event looks something like:

Event >>> Computer Event Handler

The Computer Event Handler may be nothing at all. For example, left-clicking a plain, unlinked image doesn’t do anything.

With event handling, covered in my earlier article, we can add extra functionality to this process:

Event >>> Extra Event Handler >>> Computer Event Handler

With event cancelling, we can also break this chain:

Event >>> Extra Event Handler and Cancel Event

Because in this case we cancel the event, the Extra Event Handler is executed, but then we travel no further and we do not engage the Computer Event Handler

For the onsubmit example mention earlier, a flow chart for the code would look like:

onsubmit >>> Extra Event Handler formvalidation() function is called >>>
if Form Valid >>> onsubmit Computer Event Handler is called
else
if Form Not Valid >>> onsubmit event is cancelled

We now have branching capability inside our event handling model, which allows us to detect conditions and respond to them, intercepting the computer’s normal flow.

Implementing an event cancel can be done in one of two ways. We can return false from a function called by an event handler, or use the event object’s property returnValue.

return false

Using return false inside an event handler cancels the event. For example:

<HTML>
<HEAD>
<TITLE>Cancelling Hyperlinks</TITLE>
</HEAD>
<BODY>
<A HREF=”c:” onclick=”return false;”>C drive</A>
</BODY>
</HTML>

Usually, the event sequence for a hyperlink is:

onclick >>> Hyperlink to URL in HREF attribute

But this example uses event cancelling to prevent this from happening.

When you click the hyperlink, nothing happens, because we have intercepted the onclick event before it reaches the anchor element’s internal hyperlink function, and cancelled it. Now, when the onclick event is initiated, the sequence of events is:

onclick and Cancel event

There is another method we can use which achieves exactly the same effect, although there is an important difference.

event.returnValue

An event can be cancelled by setting the event.returnValue property from a function. If we set it to true, the event continues as normal, if we set it to false, the event is cancelled.

<HTML>
<HEAD>
<TITLE>Cancelling Hyperlinks with returnValue</TITLE>
</HEAD>
<BODY>
<A HREF=”c:” onclick=”event.returnValue=false;”>C drive</A>
</BODY>
</HTML>

When we click the anchor (see example), we create an event object, which contains data relevant to the event that has just occurred. One of these properties is the returnValue of the event, which we can use to determine whether or not to cancel the event. If we set this to false, we are cancelling the onclick event.

Comparing return false to event.returnValue=false

The difference between return false and event.returnValue=false is subtle, and becomes apparent when we use the methods from inside a function.

When the interpreter reaches the JavaScript statement return false, the command is acted on immediately, and we are exited from any function that we are in.

Event handlers in this context are mini-functions.

Try this code to see the influence that the order of statements has on output.

<HTML>
<HEAD>
<TITLE>Order of Statments</TITLE>
</HEAD>
<BODY>
<A HREF=”c:” onclick=”alert(‘The Hyperlink has been cancelled.’);return false;”>C drive</A>
<BR>
<A HREF=”c:” onclick=”return false;alert(‘The Hyperlink has been cancelled.’);”>Drive C</A>
</BODY>
</HTML>

If we click ‘C drive’, we are told that the hyperlink has been cancelled.

If we click ‘Drive C’, we are not.

This is because as soon as the return false command is executed, control is restored to wherever sent it, and so the alert is never reached.

This is completely different to the event.returnValue=false version of the above program:

<HTML>
<HEAD>
<TITLE>Order of Statements with returnValue</TITLE>
</HEAD>
<BODY>
<A HREF=”c:” onclick=”alert(‘The Hyperlink has been cancelled.’); event.returnValue=false;”>C drive</A>
<BR>
<A HREF=”c:” onclick=”event.returnValue=false;alert(‘The Hyperlink has been cancelled.’);”>Drive C</A>
</BODY>
</HTML>

In this case, both alerts are shown – the position of the event.returnValue=false statement makes no difference whatsoever. event.returnValue stores our INTENT for the event, but is not acted upon immediately.

Next, we shall look at event bubbling, which can allow us to simplify code and perform multiple operations with one event.

Event Bubbling

Event Bubbling is another advanced event handling technique. As I said at the beginning of this article, event bubbling uses the concept of element ownership.

With the development of the Document Object Model (DOM), all the elements on a web page are stored in a tree structure. This means that a document may own a form, which may own two radio groups, a text box and the two standard submit and reset buttons.

We can use the DOM to reference these elements, for example:

document.mainform[‘text1’].value

This statement can be used to read and to write to the text box, one of the many advantages offered by the DOM.

Through Event Bubbling, an onclick event on, say, a radio group, is ‘bubbled’ up to the form, and carries on to the document and ultimately to the window object, the topmost object of any browser.

This means that any event handlers we have defined for these higher-level objects are also activated.

To see this in action, we shall look at a form that demonstrates event bubbling.

<HTML>
<HEAD>
<TITLE>Event Bubbling</TITLE>
</HEAD>
<BODY onclick=”alert(‘<BODY>’);”>
<FORM NAME=”MAINFORM” style=”background-color:yellow” onclick=”alert(‘MAINFORM’);”>
<INPUT TYPE=”TEXT” NAME=”TEXT1″ onclick=”alert(‘TEXT1’);”>Name
<BR>
<INPUT TYPE=”RADIO” NAME=”R1″ VALUE=”RADIO1″ onclick=”alert(‘RADIO1’);”>Male
<BR>
<INPUT TYPE=”RADIO” NAME=”R1″ VALUE=”RADIO2″ onclick=”alert(‘RADIO2’);”>Female
</FORM>
</BODY>
</HTML>

Depending on where you click on the form (see example), you will get a different sequence of alerts.

As each element in our example has an onclick event handler, when we click a form element, the event activates:

(radio1, onclick)
(mainform, onclick)
(body, onclick)

If we just click the form, we only activate:

(mainform, onclick)
(body, onclick)

And if we only click the body, we only activate:

(body, onclick)

If these event handlers are not defined, then no action is taken. So, if (mainform, onclick) does not exist, then nothing would happen and the event would pass through mainform and continue onto the body.

We can also stop the event bubble, using event.cancelBubble.

event.cancelBubble

event.cancelBubble is very similar to cancelling events. We are allowed to ‘burst’ the bubble, and prevent it from carrying on up the ownership tree.

We can do this at any stage, and the event bubble will no longer exist.

Adapting the previous code, change the text box line of code to:

<INPUT TYPE=”TEXT” NAME=”TEXT1″ onclick=”alert(‘TEXT1’);event.cancelBubble=true;”>Name

All the other features are unaffected, but if you now click the text box, you will only get one alert box saying ‘TEXT1’ (see example).

We can use event bubbling to provide complex interactivity with a web page – we may have several functions all firing because of event bubbling. Imagine two <DIV> elements, one inside the other. We could use the event bubble to pass any event from the inner <DIV> element to the outer <DIV> element.

Or we can group elements together, which is useful if we have a lot of elements that use the same event handler. Instead of writing an event handler for every element, we can write one event handler for a containing element, and use the principle of event bubbling to pass any events to the containing element, which knows what to do.

Most advanced event handling involves the event object – this will be covered in the next article in this series. For now, we will look at another advanced event feature, namely Mouse Capture.

Mouse Capture

Mouse Capture is the strangest of the three concepts presented here, and can be quite tricky to visualize at first.

Mouse Capture passes all the events on a document to one element. So, if a given element has the mouse capture, then all the events that happen to the document are passed to this element.

This causes its own set of problems – for example, if all the events are passed to the element, then it is difficult to minimize or close the browser. These are window events, which are passed to the element with the capture.

So clicking the close button creates an (element, onclick) pair, and doesn’t close the window.

To give an element the mouse capture, we use:

object.setCapture();

To release mouse capture from an element, we use:

object.releaseCapture();

Mouse capture is automatically released if certain events occur.

· A context-menu is opened (right-click)
· An alert, prompt or confirm method is issued in script
· The document is scrolled
· Another application gets the main focus.

Example code for this looks like:

<HTML>
<HEAD>
<TITLE>Mouse Capture</TITLE>
<SCRIPT>
function action() {
if (event.srcElement.id==’DIV1′) DIV1.releaseCapture();
else DIV1.style.backgroundColor=Math.floor(Math.random()*16777216);
}
</SCRIPT>
</HEAD>
<BODY onload=”DIV1.setCapture();”>
<DIV ID=”DIV1″ onclick=”action();” STYLE=”position:absolute;top:10;left:10;height:100;width:200;background-color:red”>
</DIV>
</BODY>
</HTML>

Clicking anywhere on the web page changes the color of the <DIV> element, except for clicking the <DIV> element, which releases the mouse capture from the <DIV> element, and allows you to resume normal operations (in practice, your browser may override the capture and release it after two or more clicks in a navigation area).

The code may be quite difficult to follow.

We create an HTML with a <DIV> element, and attach an onclick event handler to call the function action().

When the document has completely loaded, the onload event fires. We handle this in the program, and use the fact that all the elements are now loaded and initialised to give the <DIV> element the mouse capture.

Inside the action() function, we first check to see if the <DIV> element was clicked.

if (event.srcElement.id==’DIV1′) DIV1.releaseCapture();
else DIV1.style.backgroundColor=Math.floor(Math.random()*16777216);

If so, we release the capture, if not, we randomly change the background color of the <DIV> element.

It is not completely necessary to program the code that releases the mouse capture, but this is how it is done.

A common use of mouse capture is to write pop-up menu code, where we open a pop-up menu by clicking an element, and we close it by clicking on the pop-up menu. To do this we need to know which element fired the event, and act upon this information. This code releases the mouse capture neatly and correctly.

With these advanced event-handling techniques, we have far greater control over the flow of a document, and we can use these features to produce complex procedures.

This article originally appeared on WebDevelopersJournal.com.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Popular Articles

Featured