Prevent Default Behaviour & The Passive Option

Open the project folder

In our starter files, open the index.html page from this lessons folder:

04.Events-And-The-DOM > 13.Preventing-default-behaviour-and the-passive-option

Default event behaviour

When an event is fired it has some default behaviour which occurs in the browser, and this makes sense because we want the event to do something. A simple example is a checkbox, to see this, over to the starter files:

<!-- index.html (add after last section): -->
<input type="checkbox" id="check">

Then in the events.js we can listen for the event as we have previously:

// 3. Create a function to run on each click
function handleClick(e) {
}
// 1. Select the checkbox
const checkbox = document.querySelector('#check');
// 2. Listen for a click
checkbox.addEventListener('click', handleClick);

Inside of the function, we can find out if the checkbox is checked or not, using e.target.checked:

function handleClick(e) {
  console.log(e.target.checked);
}

Give this a try in the browser (it will be in the bottom left corner). This will toggle true or false when clicked. This toggling action is the default behaviour.

Preventing default behaviour

If we did not want this we could prevent the default behaviour and handle what happens ourselves. In an earlier example we made use of a method called stopPropagation:

function addToFavourites(e) {
  e.stopPropagation();
  alert(`${e.target.parentNode.children[2].innerText}`);
}

This was available on the event object. And like this, we can make use of another method called preventDefault in the handleClick function:

function handleClick(e) {
  e.preventDefault();
  console.log(e.target.checked);
}

This will stop the default behaviour, which was to toggle the checkbox value, and you will see the console value remain true after clicking.

The passive option

We are now free to do whatever we want when the user clicks on the checkbox. On the addEventListener method, we also have an option called passive:

checkbox.addEventListener('click', handleClick, {passive: true} );

Setting this to true will stop preventDefault from ever being called. Now the default behaviour to toggle the checkbox value has been reinstated we will see an error in the console when the checkbox is clicked:

Unable to preventDefault inside passive event listener invocation.

You maybe want to do this to stop other developers from doing something in the future when we are relying on the default behaviour. Also, using the passive option can lead to better performance.

An example of this is on mobile devices. Sometimes developers prevent the default scroll behaviour to implement some fancy way of scrolling. If we are not doing something custom like this, it is better to let the browser know by adding the passive option, therefore it does not have figure it out for itself which can take time.

Using with forms

A common example of preventing the default behaviour is with forms.

To see this, add this form in place of the checkbox:

<section class="signup">
  <h3>Sign up for weekly recipes to your inbox</h3>
  <form>
    <div>
      <label for="name">name: </label>
      <input id="name" type="text">
    </div>
    <div>
      <label for="email">email: </label>
      <input id="email" type="email">
    </div>
    <div>
      <input id="submit" type="submit">
    </div>
  </form>
</section>

Remove the event listener code from the previous example then over in the browser, we can test this out. Add a name, email, and then click submit.

When we submit a form, the default behaviour is to send the form to the server, then redirect to a new/success page. We don’t have a redirect page set, so it will redirect to the same page causing the page to refresh.

This refresh loses the form data. If we wanted to validate this data first before it was sent to the server, we would need to prevent this default behaviour.

We can set this up just like with the checkbox.

event.js

// 1. get form and input elements
const form = document.querySelector('form');
const userName = document.querySelector('#name');
const userEmail = document.querySelector('#email');

// 2. Create a function to run on submit
function handleFormSubmit(e) {
  console.log(userName.value);
}

// 3. attach event listener to form when submit has been called
form.addEventListener('submit', handleFormSubmit);

Now when we submit, we can see the problem, we briefly get the console log with the user’s name, but then it refreshes and goes away. To stop this, we call preventDefault:

function handleFormSubmit(e) {
  e.preventDefault();
  console.log(userName.value);
}

The log should now remain after a submit. Now we have this data such as the name and email, we can validate it and check it is the correct format before sending to the server.

Simple form validation

Let's add a simple validation check to see if the user has entered a name, using an if statement. We have not covered if statements in detail yet, but they are a way to check if something is true:

function handleFormSubmit(e) {
  e.preventDefault();
  console.log(userName.value);
  // simple validation example
  if(userName.value === '') {
    alert('Please enter your name');
    return;
  }
}

This if statement will only run of the name value is empty. This now gives us the chance to do whatever we want with the data before sending to the server. Remember, since the page is no longer reloading, we also need to handle emptying the form fields ourselves:

function handleFormSubmit(e) {
  e.preventDefault();
  console.log(userName.value);
  if(userName.value === '') {
    alert('Please enter your name');
    return;
  }

  // reset input values
  userName.value= '';
  userEmail.value= '';

  // send to server code
  // …
}

The form inputs will now clear after the form has submitted.