6

I've inherited some JS (that I can't change) that fires a bunch of events:

jQuery(document).trigger('section:' + section);
// where "section" changes dynamically

And I want to observe for ALL of these events, and parse out the value for section, and do something different depending on it's contents.

If it didn't change I could do this:

jQuery(document).on('section:top', doStuff );

But how do I observe an event if I only know the first part of that event name?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Joshua Soileau
  • 2,933
  • 9
  • 40
  • 51
  • You can't! jQuery's `trigger` doesn't store the events anywhere, that usually happens when the event handlers are bound, so if it where the other way around, you probably could do it. Of course anything is possible, you can parse all the javascript and look for calls to `trigger`, but that's just wrong. – adeneo Dec 15 '14 at 14:36
  • I think you're out of luck, those are basically different events... That dynamic part of the event should have been an argument to the event. `jQuery(document).trigger('section',section);` Do you have no way of knowing what all valid sections are? If so, you can do `$().on('section:top section:bottom section:right section:left')` – Ruan Mendes Dec 15 '14 at 14:42
  • http://stackoverflow.com/questions/26225987/one-listener-for-all-events-in-jquery-event-namespace/26227362#26227362 – guest271314 Dec 15 '14 at 14:44
  • These events should use namespace instead – A. Wolff Dec 15 '14 at 14:50
  • @A.Wolff That is another way to do it. However, most examples of event namespaces I've seen are not used that way, it's typically to remove a handler without keeping a reference to it, as John Resig put it, http://ejohn.org/apps/workshop/adv-talk/#13, see also http://css-tricks.com/namespaced-events-jquery/. To me, it feels like that section name should just be a parameter to the event, that's how we distinguish events in all other cases, such as checking `event.target` . – Ruan Mendes Dec 15 '14 at 15:00

3 Answers3

4

You cannot listen for all events in the style of $().on('section:*'), unfortunately. If you can change the code, I would do the following:

jQuery(document).trigger({
    type: 'section',
    section: section
});

Then you listen for it and don't need to parse anything out

jQuery(document).on('section', function(e){
    if (e.section === 'top') {
        // Something happened to the top section
    }
 });

If you want to minimize your code changes, leave the old event in there, that way existing code will be unaffected.

A different approach would be to use event namespaces.

jQuery(document).trigger('section.' + section);

jQuery(document).on('section', function(e){
    if (e.namespace === 'top') {
        // Something happened to the top section
    }
});

I, however, prefer the first approach because event namespaces are most commonly used for a different purpose: to be able to remove events without being forced to keep a reference to the handler itself. See http://css-tricks.com/namespaced-events-jquery/ and http://ejohn.org/apps/workshop/adv-talk/#13. I prefer to use styles that other developers are used to, if they do the job.

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
0

I'm really not sure about your use case but you could overwrite $.fn.trigger method:

(function ($) {
    var oldTrigger = $.fn.trigger;
    $.fn.trigger = function () {
        if (arguments[0].match(/^section:/)) {
            doStuff(arguments[0].split(':')[1]);
        }
        return oldTrigger.apply(this, arguments);
    };
})(jQuery);
var section = "top";
jQuery(document).trigger('section:' + section);

function doStuff(section) {
    alert(section);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
A. Wolff
  • 74,033
  • 9
  • 94
  • 155
0

Here's what I ended up doing.

It's a combination of Juan Mendes's solution, and using a method from the prototype library

Originally, there was a function that ran this code:

myObject.adjustSection(section) {
    jQuery(document).trigger('section:' + section);
}
// I couldn't edit this function

So I extended the function with prototype's wrap method, since my project used prototype as well as jQuery.

// My custom function wrapper
// extend adjustSection to include new event trigger
myObject.prototype.adjustSection = myObject.prototype.adjustSection.wrap(
    function(parentFunction, section) {
        // call original function
        parentFunction(section);
        // fire event w/section info
        jQuery(document).trigger({
            type: 'adjustSection',
            section: section
        });
    }
);

Then, it runs the original one, but also fires my custom event that includes the section info.

Now, I can do this to observe that event and get the section type:

jQuery(document).on('adjustSection', function(event) {
    event.section; // contains the section I need
});

Of course, this means I have to utilize both prototype and jquery within the same scope, which isn't the best thing in the world. But it worked.

Joshua Soileau
  • 2,933
  • 9
  • 40
  • 51
  • Why can't you just modify `myObject.prototype.adjustSection` in its original place? I would only do this for third-party libraries where making changes to their code can make it really hard to upgrade. – Ruan Mendes Dec 15 '14 at 19:47
  • Good point, but I don't have access to change that original method declaration. – Joshua Soileau Dec 15 '14 at 20:33