0

What I want is, when an element receive an event, I want it to do "something" first, that "something" could be is to evaluate whether to call the registered event listener or not.

I able to override manually dispatching event through calling .dispatchEvent(event) method but not event sent/dispatch by browser e.g. user click on a button.

Here my attempt:

let evtDispatcher = EventTarget.prototype.dispatchEvent;
let foo = false;
EventTarget.prototype.dispatchEvent = function(evt) {
  if (foo) {
    console.log('Event Sent');
    evtDispatcher.call(this, evt);
  } else {
    console.log('No Event Sent');
  }
}

function displayMe(evt) {
  document.getElementById('span-id').innerHTML = 'Clicked';
}

let bttn = document.getElementById('bttn-id');

bttn.addEventListener('click', displayMe);
//When user click the "button" tag
// Desire result: don't call the event listener and log "No Event Sent" on console
// Actual result: event listener is called and "Event Sent" is log on console

bttn.dispatchEvent(new Event('click')); 
//manual dispatch works

Here's my attempt code on JsFiddle

Paulo
  • 63
  • 6

1 Answers1

0

The answer is "sometimes".

I wouldn't recommend trying to override dispatchEvent() or any of the other native methods, because, it won't work for a lot of things. Much of the event handling stuff happens at a level below where you can access with JavaScript.

Instead, you can try to implement it making use of event capture.

If you provide true to the useCapture parameter or capture option of an event, you'll basically give that element priority over others that aren't using capture. If you do this on html or body at the top-level, they'll get a chance to look at, and potentially stopPropagation() of the event, based on whatever arbitrary logic you want.

You can see that happening with this little sample.

const allow = document.querySelector('input');
const div = document.querySelector('div');
const span = document.querySelector('span');
const button = document.querySelector('button');

div.addEventListener('click', event => {
  console.log('div');
  
  if (!allow.checked) {
    event.stopPropagation();
  }
}, { capture: true });

span.addEventListener('click', () => console.log('span'));
button.addEventListener('click', () => console.log('p'));
<label>Allow through? <input type="checkbox"></label>
<div>
  <span>
    <button>Click Me</button>
  </span>
</div>

So, if you do this for every possible event, you can usually do what you want. There are some exceptions though, hence the "sometimes" above, which aren't super well defined and are done by browsers to try to prevent fraud and hacks and whatnot. I don't know of a single comprehensive list of where you can't override, but if you don't truly need EVERY event to do this, it might not matter.

There also isn't a wildcard event, so you'll have to hook it up to each event, but there are ways to implement a wildcard event yourself.

One final note, since you mentioned user agent. If you are trying to do this for any security purposes: don't. Or, at the very least, ensure you also still have full protections on the back-end. Any "security" on the front-end is just security theater and easily bypassed by someone with enough knowledge, no matter how well implemented.

samanime
  • 25,408
  • 15
  • 90
  • 139
  • Thanks, I will look into wildcard event. That's something I'm not tried as solution for this problem – Paulo Apr 05 '22 at 11:58