Dmytro Huz
Dmytro Huz

Reputation: 1554

An order of triggered events

There is a <div> with two classes. For every class there is a triggered event on click, separate event for every class. Is there a way to make sure that the event for class class_one always will be triggered first and always console.log("First") will be fired first.

$('body').on('click', '.class_one', function() {
  console.log("First")
})

$('body').on('click', '.class_two', function() {
  console.log("Second")
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="class_one class_two">Click me</div>

Upvotes: 2

Views: 857

Answers (1)

3limin4t0r
3limin4t0r

Reputation: 21110

Events are not triggered on classes, the are triggered on elements. If the classes "class_one" and "class_two" are set on the same element then events are called in the same order they where bound. However events bubble up, meaning the "click" event is first triggered on element clicked, then its parent and so forth.

This means if you have the ability to change the DOM, you can force the events on the element with class "class_one" to be fired first. This can be done by removing the "class_two" class from the element and wrapping it around the "class_one" element.

This behaviour is can be found described in the jQuery on documentation:

When a selector is provided, the event handler is referred to as delegated. The handler is not called when the event occurs directly on the bound element, but only for descendants (inner elements) that match the selector. jQuery bubbles the event from the event target up to the element where the handler is attached (i.e., innermost to outermost element) and runs the handler for any elements along that path matching the selector.

$('body').on('click', '.class_one', function() {
  console.log("First")
})

$('body').on('click', '.class_two', function() {
  console.log("Second")
})

$('body').on('click', '.class_one', function() {
  console.log("Third")
})

$('body').on('click', '.class_two', function() {
  console.log("Fourth")
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="class_two">
  <div class="class_one">Click me</div>
</div>


Like already said above: If the classes "class_one" and "class_two" are set on the same element then events are called in the same order they where bound.

Which can also be also found in the on documentation:

Event handlers bound to an element are called in the same order that they were bound.

This property could be used to register two events that act as a "register" and fire all events added to this "register" (a simple array in the example).

This solution doesn't require you to change the DOM, but instead requires you to change the event registration in JavaScript.

const class_one_click_fns = [],
      class_two_click_fns = [];

$('body').on('click', '.class_one', function(...args) {
  class_one_click_fns.forEach(fn => fn.call(this, ...args))
})

$('body').on('click', '.class_two', function(...args) {
  class_two_click_fns.forEach(fn => fn.call(this, ...args))
})

class_one_click_fns.push(function () {
  console.log("First")
})

class_two_click_fns.push(function () {
  console.log("Second")
})

class_one_click_fns.push(function () {
  console.log("Third")
})

class_two_click_fns.push(function () {
  console.log("Fourth")
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="class_one class_two">Click me</div>

Upvotes: 4

Related Questions