Utilize Custom Events in jQuery using on() and trigger()
Handling client side DOM events such as click and keypress is a common task
in the jQuery code. The DOM events are always bound to some or the other HTML
element. However, there can be situations where you may need to flag some
application specific behavior or event. For example, you might be having an Ajax
code that periodically checks the server for availability of some data. As soon
as the data is made available by the server you may need to notify to your
client side code about its availability so that your code can take an
appropriate action. Obviously, there is no DOM event that can be used in this
case. Luckily, jQuery allows you to define your own events that can be raised
from within your code. This article shows how jQuery's on()
and trigger() methods can be used for the task just mentioned.
Let's try to use custom events in a sample scenario. Suppose you have an Ajax
driven function GetData() that polls the server to check whether data is
available or not. Once the data is available you want to update several DOM
elements from the page based on the data as well as perform some application
specific processing. One way to deal with this situation is to write all the
logic in the success handler of $.ajax() method. The following code shows how
this can be done:
function GetData()
{
$.ajax({
url: "/home/getdata",
type: "GET",
contentType: "application/json",
dataType: "json",
success: function (data) {
//...
//your code here
//...
}
});
}
As you can see, the GetData() client side function calls /Home/GetData action
method of Home controller. The success callback function receives the server
data and then performs all the required processing. Although this approach
works, it has a drawback. All the DOM elements that need to utilize the data
must be known to the success handler. The success handler should also know the
exact logic to be executed for each DOM element. For example, once the data is
receives TextBox1 may want to display that value, Table1 may want to append a
row with that data filled in, Div1 may want to display some message to the end
user based on that data and so on. Placing all this logic inside the success
handler makes it bulky and rigid. What if DOM elements interested in the data
received are not known at development time? What if some DOM elements want to
utilize or skip the data based on some programmatic condition? Such operations
are tedious to code in the above approach.
A better approach is to implement some sort of subscription model for the DOM
elements and then once the data is received notify the subscribers about the
data arrival. This way the success handler simply contains code to notify the
subscribers. Each subscriber deals with the data as per its own requirement. The
success handler need not know about the exact DOM elements to update at all.
This is where custom events can come handy. Once the data is received from the
server the success handler will trigger some custom event to notify the
subscribers. The subscribers, in turn, will wire an event handler to that event
and utilize the data as per their requirement inside the wired handler.
Let's see how this can be implemented. Consider a simple ASP.NET MVC view:
<form>
<input type="text" id="text1" />
<div id="div1"></div>
<input type="text" id="text2" />
<br /><br />
<table id="table1" border="1" cellpadding="5"></table>
</form>
The view contains four elements - text1, text2, div1 and table1. Except text2
all the elements are interested to get notification when the data is received
from the server.
Here is the jQuery code that defines the subscriptions:
var subscribers = [];
var pollTime = 4000;
$(document).ready(function () {
//add subscriber definition
subscribers.push({
ElementId: "text1",
Handler: function (evt, data) {
$(evt.target).val(data);
}
});
subscribers.push({
ElementId: "div1",
Handler: function (evt, data) {
$(evt.target).html("<h2>" + data + "</h2>");
}
});
subscribers.push({
ElementId: "table1",
Handler: function (evt, data) {
$(evt.target).append("<tr><td>" + data + "</td></tr>");
}
});
//attach event handlers to the subscriber elements
for (var i = 0; i < subscribers.length; i++) {
$("#" + subscribers[i].ElementId).
on("datareceived",subscribers[i].Handler);
}
//start Ajax polling
window.setTimeout(GetData, pollTime);
});
The code begins by declaring two variables - subscribers and pollTime. The
subscribers is an array that holds JavaScript objects. Each JavaScript object
stored in the subscribers array has two properties namely ElementId and Handler.
The ElementId property indicates the ID of the DOM element interested to
subscribe to the custom event. The Handler property points to an anonymous
function that acts as the event handler. In the above example text1, div1 and
table1 are the DOM elements interested in the custom event. Note that all the
handlers receive data parameter that supplies the data received from the server.
The textbox uses this data to fill itself. The <div> uses this data to display
it statically inside <h2></h2> tag. And the table appends that data as a table
row.
Now comes the important part. A for loop iterates through the subscribers
array. For every array element on() method of jQuery is called to bind
datareceived event to the handler. The datareceived is a custom event and you
can use any name instead of datareceived. This is how jQuery allows you to
handler custom events.
Then setTimeout() method starts the polling operation by specifying GetData()
function and pollTime value.
The modified GetData() function looks like this:
function GetData()
{
$.ajax({
url: "/home/getdata",
type: "GET",
contentType: "application/json",
dataType: "json",
success: function (data) {
for (var i = 0; i < subscribers.length; i++) {
$("#" + subscribers[i].ElementId)
.trigger("datareceived", data);
}
window.setTimeout(GetData, pollTime);
}
});
}
Notice the code marked in bold letters. The success function receives data
from the server. A for loop iterates through the subscribers array and for every
subscriber trigger() method is called. The trigger() method is used to raise the
custom event - datareceived. The data received from the server is passed as the
second parameter of the trigger() method.
As you can see, the success callback is quite simple and straightforward now.
All it needs is the list of subscribers and it will notify all of them by
raising the datareceived event.
The GetData() server side function used in the url parameter above looks like
this:
public JsonResult GetData()
{
return Json(DateTime.Now.ToString("hh:mm:ss tt"),
JsonRequestBehavior.AllowGet);
}
The GetData() action method simply returns current time in hh:mm:ss format.
If you run the application you should see the datareceived event being
handled as expected.

Notice that since text1, div1 and table1 subscribe to the datareceived event,
only those elements are updated. The text2 element doesn't subscribe to the
datareceived event and hence it is empty.