About Custom Events

Contact Us or call 1-877-932-8228
About Custom Events

About Custom Events

It can be difficult at first to understand why you'd want to use custom events, when the built-in events seem to suit your needs just fine. It turns out that custom events offer a whole new way of thinking about event-driven JavaScript. Instead of focusing on the element that triggers an action, custom events put the spotlight on the element being acted upon. This brings a bevy of benefits, including:

  • Behaviors of the target element can easily be triggered by different elements using the same code.
  • Behaviors can be triggered across multiple, similar, target elements at once.
  • The event source does not need to know in detail how to tell the target element what to do -- it merely needs to tell the target that the event occurred, and the target can then decide what to do

Why should you care? An example is probably the best way to explain. Suppose you have a form designer application using Ajax. Users can click on a button in a dialog box to add an element, like a button, to the interface they are designing.

Without custom events, you could use one of two approaches:

  1. The code for the interface you are designing (or just the page as a whole) could register with the button for the event. Problems with this approach include:
    • There are probably multiple buttons in the dialog for different elements or purposes, so the code would need to register for all of them
    • If the dialog box is changed, perhaps to use a drop-down combo box with a change event instead of a button click event, the event-registering code will need to be changed.
  2. The code in the dialog could listen for the click event, and invoke related methods on the interface.
    • There is one main drawback here -- the dialog code will need to know specific details about the interface (like what method to call and what data to pass to it).

Examples Without Using Custom Events

Without custom events, you might write some code like this, where the dialog box code would invoke a specific function in the interface.

Code Sample:

jqy-custom-events/Demos/formdesigner-push.html
---- C O D E   O M I T T E D ----

<script>
$(document).ready(function() {
	// in the ui object
	var $ui = $('#ui');
	
	// this is the method that adds a text box
	$ui.addTextBox = function(data) {
		$ui.children('form').append($(
			'<label>' + data.label + 
			' <input type="text" name="' + data.name + '"/></label><br />'));
	}

	// in the dialog
	var $dialog = $('#dialog');
	$dialog.label = $dialog.find('[name=label]');
	$dialog.name = $dialog.find('[name=name]');
	// push the event to the handler
	$dialog.find('[name=add]').click(
		function(e) {
			$ui.addTextBox(
				{
					label: $dialog.label.val(), // values from other elements
					name: $dialog.name.val(),   // in the dialog
				}
			);
		}
	);
});
</script>

---- C O D E   O M I T T E D ----

This demo uses a push strategy, where the dialog pushes information to the UI by invoking its addTextBox method. The main issue here is that the dialog must know the method to call in the affected object (ui), and what parameters to pass. Defining the situation is the responsibility of the affected object, and it's up to the dialog to adhere to that. In OOP terms, the dialog "must know the semantics of the UI". Also, if there were multiple objects interested in the event, the dialog would need to invoke each one's appropriate function.

Code Sample:

jqy-custom-events/Demos/formdesigner-pull.html
---- C O D E   O M I T T E D ----

<script>
$(document).ready(function() {
	// in the ui object
	var $ui = $('#ui');
	var $dialog = $('#dialog');
	
	// this is the method that adds a text box
	$dialog.find('[name=add]').click(
		function() {
			// pull the event data from the dialog
			$ui.children('form').append($(
			'<label>' + $dialog.label.val() + 
			' <input type="text" name="' + $dialog.name.val() + '"/>' +
			'</label><br />'));
		});

	// in the dialog
	$dialog.label = $dialog.find('[name=label]');
	$dialog.name = $dialog.find('[name=name]');
});
</script>

---- C O D E   O M I T T E D ----

This demo uses a pull strategy, where the UI pulls information from the dialog when the event occurs. Here the situation is reversed -- now the UI must know the semantics of the dialog. Also, if there were multiple objects interested in the event, each one would have fairly complicated code to register for event notifications.

Examples Using Custom Events

With custom events, your code might look more like this:

Code Sample:

jqy-custom-events/Demos/formdesigner-custom-event.html
---- C O D E   O M I T T E D ----

<script>
$(document).ready(function() {
	var $dialog = $('#dialog');
	var $ui = $('#ui');
	$dialog.label = $dialog.find('[name=label]');
	$dialog.name = $dialog.find('[name=name]');
	
	$dialog.find('[name=add]').click(
		function(e) {
			$dialog.triggerHandler(
				"addTextBox",
				{
					label: $dialog.label.val(), // values from other elements
					name: $dialog.name.val()    // in the dialog
				}
			);
		}
	);

	// in the ui div
	$ui.addTextBox = function(e, data) {
		$ui.children('form').append($(
	    '<label>' + data.label + 
			'<input type="text" name="' + data.name + '"/></label><br />'));
	}
	$dialog.bind(
		"addTextBox",     // event name we made up
		$ui.addTextBox	  // function in the ui
	);
	
});
</script>

---- C O D E   O M I T T E D ----

Here, the dialog just fires off an event to any interested listener. Defining the data is now the responsibility of the dialog, and the handling object can register to listen for the events, and unpack the data provided by the dialog when the event occurs.

Recap: $.fn.on, $.fn.trigger, and $.fn.triggerHandler

In the world of custom events, there are three important jQuery methods: $.fn.on, $.fn.trigger, and $.fn.triggerHandler. In the Events chapter, we saw how to use the on method for working with user events. We also saw that we could trigger events using a convenience method.

We could have triggered the events using trigger or triggerHandler, but, for browser events usually the convenience method is easiest.

For this chapter, it's important to remember two things:

  • The $.fn.on method takes an event type and an event handling function as arguments. Optionally, it can also receive event-related data as its second argument, pushing the event handling function to the third argument. Any data that is passed will be available to the event handling function in the data property of the event object. The event handling function always receives the event object as its first argument.
  • The $.fn.trigger method takes an event type string as its argument. Optionally, it can also take an array of values. These values will be passed to the event handling function as individual arguments after the event object.
    • Events, like 'click', that are fired using trigger will bubble up the DOM tree.
    • Events triggered using this method will invoke a default action, but that action can be canceled with e.preventDefault().
    • This method operates on all elements in the collection it is invoked upon.
  • $.fn.triggerHandler is similar in terms of parameters, but different in terms of bubbling and default action.
    • Events that are fired using triggerHandler will not bubble up the DOM tree.
    • Events triggered using this method will not invoke a default action.
    • This method operates only on the first element in the collection it is invoked upon.
  • The content in this activity and throughout this course is based on material from jQuery Fundamentals, Copyright Rebecca Murphey and used with permission.

Next