6

Does anyone know the magic required to get jQuery .trigger() to trigger a custom event that's handled by a (not jQuery) native JavaScript event handler?

test = document.querySelectorAll('.test')[0];
test.addEventListener('click', function() {
    console.log('click')
});
test.addEventListener('custom', function(ev) {
    console.log('custom', ev.detail)
});

// Custom Native -> Native works as expected
test.dispatchEvent(new CustomEvent('custom', {detail: 'detail'})); // -> "custom" "detail"

// Standard jQuery -> Native works as expected
$(test).trigger('click'); // -> "click"

// Custom jQuery -> Native does not work
$(test).trigger('custom'); // -> No log?
$(test).trigger({type: 'custom'}); // -> No log?

codepen.io live example

Edited to add:

A bit more details on my use case. I'm developing a library that relies on custom events but doesn't itself use jQuery. However, I'd like to make the library convenient for those applications that do have jQuery.

4 Answers 4

3

Well, after stepping through the jQuery source in a debugger, it looks like there is a solution. Not elegant, but workable. The trick is to add an onxxxx property to the element, where xxxx is the event name. The addition to the code in the question would be:

test.oncustom = function(ev, data) {
    // ev is the jQuery Event object
    // data is data passed to jQuery `.trigger()`
}

Note that jQuery does not add custom data to, for example, ev.detail, as would be the case for a standard event. Instead it passes custom data as an additional parameter.

Sign up to request clarification or add additional context in comments.

Comments

2

My idea is to create a plugin which will serve as a wrapper around trigger function in jquery:

(function($) {
  $.fn.extend({
    trigger: function(type, data) {
      return this.each(function() {
        if (typeof type == "string" && type.startsWith("test:")) {
          this.dispatchEvent(new window.CustomEvent(type, data));
        }else{
           jQuery.event.trigger(type, data, this)
         }
      });
    }
  });
})(jQuery);

It is slightly modified code from: https://github.com/jquery/jquery/blob/master/src/event/trigger.js#L185

Assuming that you add handler as follows:

test.addEventListener('test:custom', function(ev) {
  console.log('test:custom', ev.detail)
});

You can dispatch it by:

$(test).trigger('test:custom', {  detail: 'jquery'});

The downside is that you need to prefix all your custom events with some kind of namespace.

JSFiddle

1 Comment

I like your thinking, but alas it doesn't really fit my use case. I'll add a note to the problem description with more details. It's the best answer so far to my original question, though.
0

https://learn.jquery.com/events/introduction-to-custom-events/

At the end of the webpage see:

Here is an example of the usage of .on() and .trigger() that uses custom data in both cases:

$( document ).on( "myCustomEvent", {
    foo: "bar"
}, function( event, arg1, arg2 ) {
    console.log( event.data.foo ); // "bar"
    console.log( arg1 );           // "bim"
    console.log( arg2 );           // "baz"
});

$( document ).trigger( "myCustomEvent", [ "bim", "baz" ] );

2 Comments

Right, but that's not the problem. I want jQuery to trigger a custom event that's handled by a native (non-jQuery) handler.
Sorry I misinterpreted the question
0

It's not a magic. The problem located in jQuery's resolving procedure on elem[type]. Your test element doesen't have custom handler but instead has a native click handler.

So, your dirty-fix might look such as:

**test.custom = function () {console.log('custom fixed')};**

Please have a look at a code-snippet from jquery-1.7.2.js below:

// Call a native DOM method on the target with the same name name as the     event.
// Can't use an .isFunction() check here because IE6/7 fails that test.
// Don't do default actions on window, that's where global variables be (#6170)
// IE<9 dies on focus/blur to hidden element (#1486)
if (ontype && elem[type] && ((type !== "focus" && type !== "blur") ||   event.target.offsetWidth !== 0) && !jQuery.isWindow(elem)) {
// Don't re-trigger an onFOO event when we call its FOO() method
old = elem[ontype];

if (old) {
    elem[ontype] = null;
}

// Prevent re-triggering of the same event, since we already bubbled it above
jQuery.event.triggered = type;
elem[type]();
jQuery.event.triggered = undefined;

if (old) {
    elem[ontype] = old;
}

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.