How to add event object to a callback function?

Adding an event handler is pretty easy.

Now I’d like to inhibit default behavior, e.g. highlighting a text when keeping it touched for a while.

I found the preventDefault method. However I don’t see how to provide the required event object to myFunction

<!DOCTYPE html>
<html>
<body>
<h1>Event Handling</h1>
<p ontouchstart="myFunction(true)" ontouchend="myFunction(false)">Touch this! </p>
<p id="demo">demo</p>

<script>
function myFunction(state) {
  document.getElementById("demo").innerHTML = (state? "Hello World": " ");
  event.preventDefault();  // how to get access to the event object ?
}
</script>

</body>
</html>

Or am I on the wrong search path?

Answer

Adding an event handler is pretty easy.

It is. But, you’re doing it the 25+ year old legacy way, which should not be used today.

The event object is not automatically passed to callbacks when you use the legacy inline event attributes, such as onXyz.

Instead, use the modern approach to event handling and use .addEventListener() separately in your JavaScript. Then, the event object reference will automatically be passed as the first argument to your callback.

Now, because you want to pass your own argument to your callback, you’ll need to wrap your actual callback in an anonymous function that will be the the “official” event handler and that one will receive the event argument. Then, in that wrapper, you can call your desired function and pass along the event as well as your custom argument(s).

Since not all devices support touch events, you need to check to see if they are supported by the device before you use them. Below, I’ve done a basic feature detection check, but read this for more comprehensive approaches.

In addition, you may also want to prevent the event from bubbling up to ancestor elements that may have event handlers registered to them as well. If so, you should also add event.stopPropagation().

Also, you should avoid .innerHTML when you can (almost always) as it has performance and security implications. Since you aren’t actually getting or setting any HTML, use .textContent.

<!DOCTYPE html>
<html>
<body>
<h1>Event Handling</h1>
<p class="touch">Touch this! </p>
<p id="demo">demo</p>

<script>
  // Get your DOM references just once instead of each time your functions run
  const touchP = document.querySelector(".touch");
  const demo = document.getElementById("demo");

  // Not all devices support touch events, you should check first.
  if(touchP.touchstart){
    // The registered callback function will automatically be passed an event reference
    touchP.addEventListener("touchstart", function(event){
      // You can now call your desired function and pass the event and your argument
      myFunction(event, true); 
    });

    touchP.addEventListener("touchend", function(event){
      myFunction(event, false)
    });
  } else {
    demo.textContent = "Touch not supported on this device.";
  }

  function myFunction(event, state) {
    event.preventDefault();
    event.stopPropagation(); // If you don't want the event to bubble

    // You probably didn't want a space character returned if state == false.
    // Instead, return an empty string: ""
    demo.textContent = state ? "Hello World" : "";
  }
</script>

</body>
</html>