Practical .NET

ASP.NET: Managing DOM Events Interoperably

Peter Vogel introduces you to the new dynamic event model for JavaScript that's available in all the contemporary browsers.

While all the buzz is around the new elements in HTML5 (and when they will be supported in the various models), the new DOM event model hasn't gotten as much attention, which is too bad because it's implemented and ready to use in all the contemporary browsers. The new model provides a flexible way to attach events to objects/elements in the page while cleanly separating the code for wiring up events from HTML. The new model also makes it very easy to define, fire and catch your own custom events.

In this new world, you don't "fire" or "raise" events—you "dispatch" them. To process events you add a listener to an element. When an event is dispatched it propagates up through the tree of elements in the page, triggering any listeners on the elements it passes through.

For this example, I'll use a simple example of a table and a button, nested within a div element (which, in turn, is nested within the DOM's document and window objects):

 <div id="MyDiv">
<table id="MyTable">
..table definition
<input id="MyButton" type="button" value="Post Data">

In real life, I might want to capture events for individual cells or rows in the table but, for clarity's sake, I'll just assume that I want to capture the click event that's fired when the user clicks anywhere in the table.

Processing Default Events

Since the table will, all by itself, fire a click event, my first step is to tie an event listener to the table element to listen for click events. The jQuery code to find the element with an id attribute of MyTable and tie a function called processTable to an event called 'click' looks like this (I'll come back to the third parameter being passed to processTable shortly):

  $("#MyTable").each(function () {
this.addEventListener("click", processTable, false);

Of course, I could have tied a click event to every row by using $("tr") as my jQuery selector.

The processTable function that, in this example, will be called when the click event for the table is dispatched can accept a single parameter (that parameter is automatically provided by the DOM event model). My function would look like this:

 function processTable(e) {
…process table click event…

The parameter that's passed contains a wealth of information. Its target property, for instance, gives you access to the element that fired the event.

However, the event doesn't stop moving up through the elements in the page just because a listener processes it. This means I could have tied my click event listener to the div element and still process the click event fired by the table. That listener would also catch the click event fired by the button within the div element. That design would make sense if the processing for the two events was similar (and, if there were differences, I could check the property to determine whether it was the button or the table that had fired the click event).

You can manage that propagation process in two ways. First, when you add an event listener, you can specify that this listener is to get the event before any other listener by passing true in the addEventListener's third parameter. This code, for instance, adds an event listener to the document but specifies that all click events from any element in the page are to go to this listener first before continuing up through the normal propagation path:

document.addEventListener("click", helloDiv, true);

Within an event listener, I can prevent an event from propagating up the tree by calling the stopPropagation method on the parameter passed to the function (this method's name may change to stopImmediatePropagation when the specification is finalized—IE 9 supports both names). This example prevents any subsequent listener seeing the event:

 function processTable(e) {
…process table click event…
Dispatching Your Own Events

If you want to dispatch your own events from within your functions, first define your event using the document object's createEvent method. When you create an event, you specify the event model you want to use. This controls, for instance, what properties will appear on the parameter passed to the function that handles the event. There are several libraries including one dedicated to user interface event (UIEvents). In this example, I'm using the standard Event library:

 var e =  document.createEvent("Event");

After you've created an event, you need to give it a name and specify whether it can bubble up or be cancelled. In this example, I'm specifying that the event won't bubble but can be cancelled:

 e.initEvent("MyEvent", false,  true);

Adding a listener for this event would look like this:

 window.addEventListener("MyEvent", processMyEvent, false);

Finally, to dispatch this event from within your code, you call the dispatchEvent on any element:       


These are the key functions in the new event model (there's more, of course). What's most attractive to me about the model is how consistent it is among the contemporary browsers -- very good news for Web developers.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at

comments powered by Disqus


  • Creating a Progressive Web App with Blazor WebAssembly

    Not surprisingly, it's dead easy to create an app in Blazor that runs outside of the browser window and (potentially) in an offline mode. Before you get carried away, though, there are some key design decisions to make.

  • GitLab Takes Over VS Code Extension, Plans Improvements

    DevOps specialist GitLab has officially taken over the control of a GitLab extension for Microsoft's open source, cross-platform Visual Studio Code editor.

  • VS Code Python Tool Now Does Native Notebooks

    The Python Extension for VS Code Insiders team is previewing the newest implementation of notebooks, used frequently in data science with offerings such as Jupyter Notebooks.

  • As .NET 5 Nears, Content/Documentation Reorganization Starts

    A GitHub project is seeking to reorganize documentation and developer content in advance of the November debut of .NET 5, a unification of all things .NET that combines. .NET Core and other components.

  • Windows Devs Get Cross-Platform Page, Issues Repo

    Developers doing their coding on the Windows OS have received two new resource gifts from Microsoft: a new landing page for those using cross-platform technologies and a new GitHub repo with which to report issues to Windows engineering teams.Developers doing their coding on the Windows OS have received two new resource gifts from Microsoft: a new landing page for those using cross-platform technologies and a new GitHub repo with which to report issues to Windows engineering teams.

.NET Insight

Sign up for our newsletter.

Terms and Privacy Policy consent

I agree to this site's Privacy Policy.

Upcoming Events