0

Is there a way to control execution order of JS scripts bound to element click? For example, we have two separate scripts, that are fired on the same action and for the same element.

First script (fired by script on website - which I have no permission to change):

$('body').on('click', '#button', function1);

And the second script (which is fired by browser plugin, which I can change, and would run after everything else was fired):

$('body').on('click', '#button', function2);

Those two scripts are separated (in two different files) and cannot be merged into one like this, because I can change only the second one:

$('body').on('click', '#button', function() {
    function1();
    function2();
});

Can I set the order of execution? Can I force one script to be executed last?

Sᴀᴍ Onᴇᴌᴀ
  • 8,218
  • 8
  • 36
  • 58
b4rt3kk
  • 1,419
  • 3
  • 17
  • 26
  • First listener assigned should be first to fire. So script order might help Other than that what specific problem are you trying to solve? – charlietfl Oct 04 '16 at 19:22
  • @charlietfl I've made a chrome extension for a specific webpage (not mine). And that would be nice if I could fire some additional actions after those fired by page - for example page is loading some comments via JS when u click the button. I would like, after a load is done, filter and replace content of them. – b4rt3kk Oct 04 '16 at 19:27
  • 1
    Have a look at [Ensure jQuery event handler execution order](http://stackoverflow.com/q/9037105/1048572). But really, what's your [actual problem](http://meta.stackexchange.com/q/66377)? – Bergi Oct 04 '16 at 19:27
  • 2
    @b4rt3kk in that case, you'd need to listen for the load event, or even better watch for the DOM insertion; the button click is pretty irrelevant for that – Bergi Oct 04 '16 at 19:28
  • Why can't you disable the first one? In your second script, just do `$('body').off('click', '#button').on('click', '#button', yourfunction)`. – trincot Oct 04 '16 at 19:28
  • @trincot I can't disable first script, cuz it's a part of a site, which I would like to be still functional to user. – b4rt3kk Oct 04 '16 at 19:59
  • I am not saying you need to disable the script. I am asking why in your second script you cannot undo and replace the event listener. – trincot Oct 04 '16 at 20:21

1 Answers1

0

In your second script you can read which function was bound to the click event by the first script. Then you can detach that handler and add your own, where you can (if you want) add the execution of the original function in the last step:

// script 1 ///////////////////////////////////////////////////////////
function f1() {
    console.log('f1: function bound by script 1');
}
$('body').on('click', '#button', f1);

// script 2 ///////////////////////////////////////////////////////////
function f2() {
    console.log('f2: my own function that should run first');
}

var original_f = $._data(document.body, 'events').click[0].handler;
$('body').off('click', '#button').on('click', '#button', function () {
    f2();
    original_f();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="button">Trigger handlers</button>

This makes use of $._data, which is not part of the public API of jQuery. See this answer.

Remarks

The above solution assumes that

  1. the site's script (the first script) uses jQuery event delegation on the body element for the element #button; as follows:

    $('body').on('click', '#button', function1);
    

    Note that there are other ways to attach event handlers, but this answer assumes that the first script does it like this (as you provided in the question). Of course, function1 can be any function, or even an anonymous, in-line function.

  2. You have full control over the second script and can redefine the click handler you have defined in it.

You write in comments that you cannot access the function of the first script (function1). But please realise that if JavaScript is able to execute it, there is no reason why you could not have access to it via JavaScript.

Furthermore, since you informed that the first script uses jQuery to attach their handler, also jQuery knows which function it is and can access it (how else could it execute it when a click event happens?).

The solution I provide above actually asks jQuery to provide you the reference to that function. And then you can execute it just like jQuery would do when a click event occurs.

Testing the presence of the handler

In order to verify that indeed the first script has set a handler in this way:

$('body').on('click', '#button', function1);

... and that is still there, you can use the following script for debugging:

// script 1 -- you don't need to enter this, it is for this snippet to work with.
function f1() {
    console.log('f1: function bound by script 1');
}
$('body').on('click', '#button', f1);

// script 2 -- your code ///////////////////////////////////////////////////////////

var click_handlers = $._data(document.body, 'events').click;
console.log('Info on BODY click handlers that have been set via jQuery:\n',
             JSON.stringify(click_handlers, null, 2));

console.log('First click handler is this function:\n', click_handlers[0].handler);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Community
  • 1
  • 1
trincot
  • 317,000
  • 35
  • 244
  • 286
  • The problem is, that I can't use original_f() because I don't have access to it. Of course I can rewrite it but when owner of a site will change anything I would need to change my definition too. As I mentioned - my handler is attached as a plugin. – b4rt3kk Oct 04 '16 at 22:13
  • I don't understand what you mean with *"I don't have access to it"*. If JavaScript can execute it, that means you have access to it from JavaScript. Please see the comments I have added to my answer. Probably there is some misunderstanding on my side. Could you check if my assumptions are correct, and try the "script 2" part I have provided in the second snippet to see what it outputs for you? – trincot Oct 05 '16 at 08:15