Prevent duplicate Event bindings in jQuery

Sky Bit
4 min readJul 30, 2020

--

A web developer writes jQuery events on a daily basis in their projects. Events are a lifesaver when considering code managing, modulation and code separation and also, elimination of repeated code blocks

Some events are registered into the whole document, some are registered to some specific elements. But these events can be a disaster when they are registered dynamically. In some cases, we bind one event on the result of another process or action or even another event. In that case, some process of action can be occurred multiple times on the page, resulting in multiple times one event got registered.

So, while you want the event to be registered once, get resulted in multiple registrations. So, in one action, the same event will be called multiple times.

Example:
Here, we are taking an example of one login screen and the scenario is: if the password is valid, then only show the Login button and when the password is invalid, hide the login button.

$('#password').on('keyup', (event) => {
//Password validation
if ('' !== event.target.val()) {
//Show the button
$('#login-button').css('display', 'block');
// Ebnable action on button click
$('#login-button').on('click', () => {
submitFormDataToAPI();
});
} else {
$('#login-button').css('display', 'none');
}
});
/**
* Login data to send to API
*/
const submitFormDataToAPI = () => {
$.ajax({
//
})
};

As you can see, we are showing the login button when the password is valid and with that, we are also binding the login event to call the AI with required data. But the password can be changed by the user anytime and it can be valid/invalid several times, resulting in multiple click event bindings.

So, what we can do?

1. We can register the event once while the page is loaded, but we don’t want to register it as more events can result in slower rendering and heavy resource usage on the client’s system. (We are considering 1000s of events)

$(document).ready(() => {
$('#login-button').on('click', () => {
submitFormDataToAPI();
});
});

const submitFormDataToAPI = () => {
$.ajax({
//
})
};

2. We can add a parameter as isEventRegistered and maintain a state of the event.

/**
* State of the Login button
*
@type {boolean}
*/
let isLoginButtonEnabled = false;
$('#password').on('keyup', (event) => {
if ('' !== event.target.val()) {
if (!isLoginButtonEnabled) {
//Show the button
$('#login-button').css('display', 'block');
// Ebnable action on button click
$('#login-button').on('click', () => {
submitFormDataToAPI();
});
isLoginButtonEnabled = true;
}
} else {
$('#login-button').css('display', 'none');
}
});
const submitFormDataToAPI = () => {
$.ajax({
//
})
};

3. We will deregister the event everytime while password is not validated.

$('#password').on('keyup', (event) => {
if ('' !== event.target.val()) {
//Show the button
$('#login-button').css('display', 'block');
// Ebnable action on button click
$('#login-button').on('click', () => {
submitFormDataToAPI();
});
} else {
$('#login-button').css('display', 'none').off('click');
}
});
const submitFormDataToAPI = () => {
$.ajax({
//
})

But we are on case of invalid password, deregistering the generic click event. That will result in deregisteringall click events of that Login button.

4. We can name the events by a particular name so that it will be easy for us to manage the events.

$('#password').on('keyup', (event) => {
if ('' !== event.target.val()) {
//Show the button
$('#login-button').css('display', 'block');

// Ebnable action on button click
$('#login-button').on('click.loginAction', () => { // the name of click action is "loginAction"
submitFormDataToAPI
();
});
} else {
$('#login-button').css('display', 'none').off('click.loginAction');
}
});

const submitFormDataToAPI = () => {
$.ajax({
//
})
};

In this way, we don't need to have any state for the click event and if you deregister the event, it will only unbind the particular event. Other events will be intact. And also, the previous click event will be replaced with the new one. There will not be a new event get registered, rather than, the older one will get replaced.

5. Also, we can optimize the code by adding .off(‘click.loginAction’) immediately before the .on(‘click.loginAction’, () => {})
In this way, we don't have to deregister any events if we want to deregister all the events and add a new one. We can do it in one line:

$('#password').on('keyup', (event) => {
if ('' !== event.target.val()) {
//Show the button
$('#login-button').css('display', 'block');

// Ebnable action on button click
$('#login-button').off('click.loginAction').on('click.loginAction', () => {
submitFormDataToAPI();
});

//
$('#login-button').off('click.loginPopup').on('click.loginPopup', () => {
window.alert('Logging in');
});

// show loader
$('#login-button').off('click.loginPopup').on('click.loginPopup', () => {
displayPopup(true);
});
} else {
$('#login-button').off('click').on('click', () => {
console.log('Password criteria not met');
});
}
});

Here, if the password is not valid, it will deregister all click events in the login button and immediately assign a new one. So, we don't have to manually deregister each of them separately.

Thanks
Sky Bit
skybit.bbsr@gmail.com

--

--