Custom events in jQuery?

JqueryEvents

Jquery Problem Overview


I'm looking for some input on how to implement custom eventhandling in jquery the best way. I know how to hook up events from the dom elements like 'click' etc, but I'm building a tiny javascript library/plugin to handle some preview functionality.

I've got a script running to update some text in a dom element from a set of rules and data/user input I got, but now I need that same text shown in other elements that this script can't possibly know of. What I need is a good pattern to somehow observe this script producing the needed text.

So how do I do this? Did I overlook some builtin functionality in jquery to raise/handle user events or do I need some jquery plugin to do it? What do you think is the best way/plugin to handle this?

Jquery Solutions


Solution 1 - Jquery

The link provided in the accepted answer shows a nice way to implement the pub/sub system using jQuery, but I found the code somewhat difficult to read, so here is my simplified version of the code:

http://jsfiddle.net/tFw89/5/

$(document).on('testEvent', function(e, eventInfo) { 
  subscribers = $('.subscribers-testEvent');
  subscribers.trigger('testEventHandler', [eventInfo]);
});

$('#myButton').on('click', function() {
  $(document).trigger('testEvent', [1011]);
});

$('#notifier1').on('testEventHandler', function(e, eventInfo) { 
  alert('(notifier1)The value of eventInfo is: ' + eventInfo);
});

$('#notifier2').on('testEventHandler', function(e, eventInfo) { 
  alert('(notifier2)The value of eventInfo is: ' + eventInfo);
});

Solution 2 - Jquery

Take a look at this:

(reprinted from the expired blog page http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ based on the archived version at http://web.archive.org/web/20130120010146/http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/)</sub>


Publish / Subscribe With jQuery

June 17th, 2008

With a view to writing a jQuery UI integrated with the offline functionality of Google Gears i’ve been toying with some code to poll for network connection status using jQuery.

The Network Detection Object

The basic premise is very simple. We create an instance of a network detection object which will poll a URL at regular intervals. Should these HTTP requests fail we can assume that network connectivity has been lost, or the server is simply unreachable at the current time.

$.networkDetection = function(url,interval){
	var url = url;
	var interval = interval;
	online = false;
	this.StartPolling = function(){
		this.StopPolling();
		this.timer = setInterval(poll, interval);
	};
	this.StopPolling = function(){
		clearInterval(this.timer);
	};
	this.setPollInterval= function(i) {
		interval = i;
	};
	this.getOnlineStatus = function(){
		return online;
	};
	function poll() {
		$.ajax({
			type: "POST",
			url: url,
			dataType: "text",
			error: function(){
				online = false;
				$(document).trigger('status.networkDetection',[false]);
			},
			success: function(){
				online = true;
				$(document).trigger('status.networkDetection',[true]);
			}
		});
	};
};

You can view the demo here. Set your browser to work offline and see what happens…. no, it’s not very exciting.

Trigger and Bind

What is exciting though (or at least what is exciting me) is the method by which the status gets relayed through the application. I’ve stumbled upon a largely un-discussed method of implementing a pub/sub system using jQuery’s trigger and bind methods.

The demo code is more obtuse than it need to be. The network detection object publishes ’status ‘events to the document which actively listens for them and in turn publishes ‘notify’ events to all subscribers (more on those later). The reasoning behind this is that in a real world application there would probably be some more logic controlling when and how the ‘notify’ events are published.

$(document).bind("status.networkDetection", function(e, status){
	// subscribers can be namespaced with multiple classes
	subscribers = $('.subscriber.networkDetection');
	// publish notify.networkDetection even to subscribers
	subscribers.trigger("notify.networkDetection", [status])
	/*
	other logic based on network connectivity could go here
	use google gears offline storage etc
	maybe trigger some other events
	*/
});

Because of jQuery’s DOM centric approach events are published to (triggered on) DOM elements. This can be the window or document object for general events or you can generate a jQuery object using a selector. The approach i’ve taken with the demo is to create an almost namespaced approach to defining subscribers.

DOM elements which are to be subscribers are classed simply with “subscriber” and “networkDetection”. We can then publish events only to these elements (of which there is only one in the demo) by triggering a notify event on $(“.subscriber.networkDetection”)

The #notifier div which is part of the .subscriber.networkDetection group of subscribers then has an anonymous function bound to it, effectively acting as a listener.

$('#notifier').bind("notify.networkDetection",function(e, online){
	// the following simply demonstrates
	notifier = $(this);
	if(online){
		if (!notifier.hasClass("online")){
			$(this)
				.addClass("online")
				.removeClass("offline")
				.text("ONLINE");
		}
	}else{
		if (!notifier.hasClass("offline")){
			$(this)
				.addClass("offline")
				.removeClass("online")
				.text("OFFLINE");
		}
	};
});

So, there you go. It’s all pretty verbose and my example isn’t at all exciting. It also doesn’t showcase anything interesting you could do with these methods, but if anyone’s at all interested to dig through the source feel free. All the code is inline in the head of the demo page

Solution 3 - Jquery

I think so.. it's possible to 'bind' custom events, like(from: http://docs.jquery.com/Events/bind#typedatafn):

 $("p").bind("myCustomEvent", function(e, myName, myValue){
      $(this).text(myName + ", hi there!");
      $("span").stop().css("opacity", 1)
               .text("myName = " + myName)
               .fadeIn(30).fadeOut(1000);
    });
    $("button").click(function () {
      $("p").trigger("myCustomEvent", [ "John" ]);
    });

Solution 4 - Jquery

I had a similar question, but was actually looking for a different answer; I'm looking to create a custom event. For example instead of always saying this:

$('#myInput').keydown(function(ev) {
    if (ev.which == 13) {
        ev.preventDefault();
        // Do some stuff that handles the enter key
    }
});

I want to abbreviate it to this:

$('#myInput').enterKey(function() {
    // Do some stuff that handles the enter key
});

trigger and bind don't tell the whole story - this is a JQuery plugin. http://docs.jquery.com/Plugins/Authoring

The "enterKey" function gets attached as a property to jQuery.fn - this is the code required:

(function($){
    $('body').on('keydown', 'input', function(ev) {
        if (ev.which == 13) {
            var enterEv = $.extend({}, ev, { type: 'enterKey' });
            return $(ev.target).trigger(enterEv);
        }
    });
    
    $.fn.enterKey = function(selector, data, fn) {
        return this.on('enterKey', selector, data, fn);
    };
})(jQuery);

http://jsfiddle.net/b9chris/CkvuJ/4/

A nicety of the above is you can handle keyboard input gracefully on link listeners like:

$('a.button').on('click enterKey', function(ev) {
    ev.preventDefault();
    ...
});

Edits: Updated to properly pass the right this context to the handler, and to return any return value back from the handler to jQuery (for example in case you were looking to cancel the event and bubbling). Updated to pass a proper jQuery event object to handlers, including key code and ability to cancel event.

Old jsfiddle: http://jsfiddle.net/b9chris/VwEb9/24/

Solution 5 - Jquery

It is an old post, but I will try to update it with a new information.

To use custom events you need to bind it to some DOM element and to trigger it. So you need to use

> .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.

and

> .trigger() method takes an event type as its argument. Optionally, it > can also take an array of values. These values will be passed to the > event handling function as arguments after the event object.

The code looks like this:

$(document).on("getMsg", {
    msg: "Hello to everyone",
    time: new Date()
}, function(e, param) {
    console.log( e.data.msg );
    console.log( e.data.time );
    console.log( param );
});

$( document ).trigger("getMsg", [ "Hello guys"] );

Nice explanation can be found here and here. Why exactly this can be useful? I found how to use it in this excellent explanation from twitter engineer.

P.S. In plain javascript you can do this with new CustomEvent, but beware of IE and Safari problems.

Solution 6 - Jquery

Here is how I author custom events:

var event = jQuery.Event('customEventName');
$(element).trigger(event);

Granted, you could simply do

$(element).trigger('eventname');

But the way I wrote allows you to detect whether the user has prevented default or not by doing

var prevented = event.isDefaultPrevented();

This allows you to listen to your end-user's request to stop processing a particular event, such as if you click a button element in a form but do not want to the form to post if there is an error.


I then usually listen to events like so

$(element).off('eventname.namespace').on('eventname.namespace', function () {
    ...
});

Once again, you could just do

$(element).on('eventname', function () {
    ...
});

But I've always found this somewhat unsafe, especially if you're working in a team.

There is nothing wrong with the following:

$(element).on('eventname', function () {});

However, assume that I need to unbind this event for whatever reason (imagine a disabled button). I would then have to do

$(element).off('eventname', function () {});

This will remove all eventname events from $(element). You cannot know whether someone in the future will also bind an event to that element, and you'd be inadvertently unbinding that event as well

The safe way to avoid this is to namespace your events by doing

$(element).on('eventname.namespace', function () {});

Lastly, you may have noticed that the first line was

$(element).off('eventname.namespace').on('eventname.namespace', ...)

I personally always unbind an event before binding it just to make sure that the same event handler never gets called multiple times (imagine this was the submit button on a payment form and the event had been bound 5 times)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPer Hornsh&#248;j-SchierbeckView Question on Stackoverflow
Solution 1 - JqueryManuel NavarroView Answer on Stackoverflow
Solution 2 - JqueryVitor SilvaView Answer on Stackoverflow
Solution 3 - JqueryTuxifiedView Answer on Stackoverflow
Solution 4 - JqueryChris MoschiniView Answer on Stackoverflow
Solution 5 - JquerySalvador DaliView Answer on Stackoverflow
Solution 6 - JqueryLuke MadhangaView Answer on Stackoverflow