28

I'm writing a jQuery plugin and using .on and .trigger as my pub/sub system. However, I want to trigger multiple events in different scenarios.

Is this possible to do as one string, like the .on method?

Goal:

$this.trigger("success next etc");    // doesn't work

Current solution:

$this
    .trigger("success")
    .trigger("next")
    .trigger("etc");                  // works, triggers all three events

Any suggestions?

4 Answers 4

35

JQuery itself does not support triggering multiple events, however you could write custom extension method triggerAll

(function($) {
    $.fn.extend({
        triggerAll: function (events, params) {
            var el = this, i, evts = events.split(' ');
            for (i = 0; i < evts.length; i += 1) {
                el.trigger(evts[i], params);
            }
            return el;
        }
    });
})(jQuery);

And call it like following:

$this.triggerAll("success next etc");
Sign up to request clarification or add additional context in comments.

4 Comments

Is there a benefit in using a for loop instead of an each loop?
I think for such simple case it is more effective to use regular for-in loop instead of custom jQuery $.each which does many assumptions on arguments you are passing through. And finally it does for-in inside.
Just a note that the semi-colon after the closing bracket of triggerAll should not be there.
@ZachWolf For-loops are massively more performant than $.each() or even Array.forEach(), because it saves the quite significant overhead of a function call on every iteration.
7

What you have is fine... you can't trigger multiple events using a comma separated list. The trigger() constructor only takes an event name and optional additional parameters to pass along to the event handler.

An alterternative would be to trigger all events attached to an element, however, this may not meet your needs if you need to trigger specific events in different senarios:

$.each($this.data('events'), function(k, v) {
    $this.trigger(k);
});​

2 Comments

Haha I just wrote something similar to this! Glad to see someone else came to the same conclusion. Thanks!
You can add ~['succes', 'next', 'etc'].indexOf(k) && at the start of $this.trigger(k) to filter desired events.
6

Just in case anyone else stumbles upon this question later in life, I solved this by creating a custom jQuery function.

$.fn.triggerMultiple    =   function(list){
    return this.each(function(){
        var $this = $(this); // cache target

        $.each(list.split(" "), function(k, v){ // split string and loop through params
            $this.trigger(v); // trigger each passed param
        });
    });
};

$this.triggerMultiple("success next etc"); // triggers each event

1 Comment

You didn't propagate the params.
0

You could extend the original .trigger() Method prototype:

(function($) {
  const _trigger = $.fn.trigger;
  $.fn.trigger = function(evtNames, data) {
    evtNames = evtNames.trim();
    if (/ /.test(evtNames)) {
      evtNames.split(/ +/).forEach(n => _trigger.call(this, n, data));
      return this;
    }
    return _trigger.apply(this, arguments);
  };
}(jQuery));


$("body").on({
  foo(e, data) { console.log(e, data); },
  bar(e, data) { console.log(e, data); },
  baz(e, data) { console.log(e, data); },
});


$("body").off("bar"); // Test: stop listening to "bar" EventName
$("body").trigger(" foo    bar baz ", [{data: "lorem"}]); // foo, baz
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

Code explained


// Keep a reference to the original prototype
const _trigger = $.fn.trigger;

$.fn.trigger = function(evtNames, data) {

  // Remove leading and ending whitespaces 
  evtNames = evtNames.trim();

  // If the string has at least one whitespace
  if (/ /.test(evtNames)) {

    // Split names into Array (Treats multiple spaces as one)
    evtNames.split(/ +/)
    // Call the original .trigger() method for one eventName (and pass data)
      .forEach(n => _trigger.call(this, n, data));

    // End here.
    // Return this (Element) to maintain jQuery methods chainability for this override.
    return this;
  }

  // No whitespaces detected
  // Pass all arguments to the original .trigger() Method immediately.
  // The original method already returns this (Element), so we also need to 
  // return it here to maintain methods chainability when using this override. 
  return _trigger.apply(this, arguments);
};

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.