Custom event in jQuery that isn't bound to a DOM element?
Asked Answered
A

7

50

I'm curious if its possible to create a custom event in jQuery that isn't bound to a DOM element.

I greatly prefer jQuery to YUI but there is one thing in YUI that I like, which is creating custom events and being able to subscribe to them later.

For example, this creates an event that is bound to a variable, not to a DOM element:

var myevent = new YAHOO.util.CustomEvent("mycustomevent");

All of the examples and documentation I have been reading for jQuery require something like:

$('body').bind('mycustomevent', function(){
    //do stuff
});
Appliance answered 12/10, 2009 at 8:13 Comment(3)
I guess jquery won't understand 'mycustomevent' and YUI events at all. However you might try to use the pointer: bind(myevent, ..Peatroy
i think that, similar to Django, there are some best-practices in JQuery. at first, plug-ins. You can create your custom event as an external class, being a plug-in for JQuery, and you can simply bind your event to your element using any selectors, such as $("#myDiv").myPlugin("does lots of stuff") there are several ways of doing that, but you should acknowledge first what exactly you need. can you elaborate a bit? i could try to give you more precise comment) thxCutup
Hi! They accepted answer isn't correct (or not correct anymore). Could you perhaps change the accepted answer to mine?Unequivocal
U
43

You can trigger custom global events like this in jQuery:

jQuery.event.trigger('mycustomevent', [arg1, arg2, arg3]);

These will trigger for any element.

Since jQuery is built around DOM objects, you have to bind your events to DOM objects. You can probably find some way to bind events without an element too (you did), but that's not a supported methodology.

As you wrote in your own answer, you can bind your event to a global DOM object if you don't want to bind it to an individual page element:

$(document).bind('mycustomevent', function (e, arg1, arg2, arg3) { /* ... */ });
Uphemia answered 12/10, 2009 at 8:21 Comment(2)
looks like jQuery supports this now: bugs.jquery.com/ticket/7818#comment:26, forum.jquery.com/topic/triggering-custom-events-on-js-objects. The triggerHandler workaround mentioned in the link was fixed in issue 7930 as well.Consuelaconsuelo
Yep, jQuery actually supports this now (see my answer: https://mcmap.net/q/261027/-custom-event-in-jquery-that-isn-39-t-bound-to-a-dom-element)Unequivocal
U
42

According to a comment by John Resig, binding events to custom objects via jQuery is supported:

No particular reason why it's not documented (other than that it's rather non-traditional for most users) - but yes, we support it and have unit tests for it.

So this works:

var a = {foo: 'bar'};
$(a).on('baz', function() {console.log('hello')});
$(a).triggerHandler('baz');
>>> 'hello'

Most users will need triggerHandler(), not trigger(). If .trigger("eventName") is used, it will look for a "eventName" property on the object and attempt to execute it after any attached jQuery handlers are executed (Source).

EDIT (28.02.2017):

After using this pattern for about 2 years in a large codebase, I can attest that this is a bad idea. These custom events lead to incomprehensible data flows. Prefer callbacks instead.

Unequivocal answered 26/9, 2014 at 14:57 Comment(1)
Silly question: Does it have a reason why it is not documented? Shouldn't it be used? Could it be removed/modified in a newer version? I'm wondering if I should use it in favour of other sub-pub libs like EvenEmitter.Acrosstheboard
A
6

For future readers, its fairly simple to do this. I did further research after posting my question. Unfortunately none of the other commenters were correct.

In order to bind a custom event:

$().bind('mycustomevent', function(){
    //code here
});

Also, you can build data into the event object that is later accessible:

$({mydata:'testdata'}).bind('mycustomevent',function(){
    //code here
});
Appliance answered 12/10, 2009 at 21:1 Comment(1)
You should know that with $() you're still binding it to a DOM object ($() is the same as doing $(document)). $({}) works, but you should know that it works because jQuery never checks whether it's a DOM object. It still wraps it with a jQuery object that has methods such as append(...) which will stop your script if called. Also, the behavior for wrapping non-DOM objects is undefined and may change in the future. So I still stand by my point in my answer, and recommend you to bind it to $(document) rather than a JavaScript object.Uphemia
G
5

Binding to non-dom elements has been removed in jQuery 1.4.4.

Gt answered 15/12, 2010 at 17:42 Comment(1)
Perhaps, he means plain JavaScript objects?Clonus
T
3

You can still arbitrarily trigger and respond to events using jQuery, even if you don't know what element to attach them to. Just create a "receiver" element in your document, to which you can bind all your custom events. This allows you to manage your event handling logic in one place, for all your non-element-specific events.

$(document).ready(function() {

  $(body).append('<div id="receiver">');

  $("#receiver").bind("foo_event", function () {
    // decide what to do now that foo_event has been triggered.
  });

  $("#some_element").click(function() {
    $("#receiver").trigger("foo_event");
  });

});
Thyestes answered 12/10, 2009 at 21:8 Comment(2)
I think that's a bad idea. If you really want some element to attach events to, why not use $('body') or $(document)?Uphemia
It's just a convention that works. I prefer it over using document or body because it acts sort of like a sterile clearinghouse for events -- I know everything that's in it, and there's less likelihood of something bad unwanted happening by accident. Can you explain why you think it's a bad idea?Thyestes
C
3

jQuery Callbacks provides a simple way to implement a pub-sub system independent of the DOM.

Near the bottom of the linked page is example code that shows how to do that.

Caliph answered 28/8, 2013 at 10:44 Comment(0)
P
1

[EDIT]

Here's a working class that uses the concepts written below:

https://github.com/stratboy/image-preloader

It's just a sequential image preloader. You can subscribe to a bunch of events. Take a look.

[/EDIT]

Old post:

Here's another barebones example with callbacks like suggested by Himanshu P.

I'm building a class and I come from Mootools, where things like Classes and custom events directly implemented in classes (so not bound to DOM elements) are absolutely natural. So I tried a sort of workaround and share below.

  var step_slider;

  //sandbox
  ;(function($) {

//constructor
var StepSlider = function(slider_mask_selector,options) {

    //this.onStep = $.Event('step');
    this.options = null;
    this.onstep = $.Callbacks();

    this.init();
}//end constructor

StepSlider.prototype = {

    init:function(){
        this.set_events();
    },//end init

    set_events:function(){

        if(this.options){
            if(this.options.onstep){
                this.subscribe('step',options.onstep);
            }
        }

    },//set_events

    subscribe:function(event,action){
        this['on'+event].add(action);
    },

    fire_onstep:function(){
        this.onstep.fire({ data1:'ok' });
    }

}//end prototype/class

//--------------------

$(document).ready(function() {

    step_slider = new StepSlider('selector');

    //for example, say that you have a div#next-button, you can then do this:
    $('#next-button').click(function(){
        step_slider.fire_onstep();
    });

});//end domready


})(jQuery);
Philbrick answered 2/10, 2013 at 18:18 Comment(2)
that's not a class.Shaky
@low_rents: maybe not for ES6, but as long as you can instantiate objects from it (new ClassName), it's a class. Or, it's a (old) javascript way to do something like a class, keeping in mind that javascript didn't have real oop/inheritance syntax/sugars like ActionScript 3 and ES6. Probably one of the best js oop implementations before ES6 was the way coffescript creates js classes (just create one and see the compiled code), but the above one it's a more simple implementation and it's a good compromise to get self-contained, well organised objects to be instantiated infinite times.Philbrick

© 2022 - 2024 — McMap. All rights reserved.