How to check whether dynamically attached event listener exists or not?

263,709

Solution 1

There is no way to check whether dynamically attached event listeners exist or not.

The only way you can see if an event listener is attached is by attaching event listeners like this:

elem.onclick = function () { console.log (1) }

You can then test if an event listener was attached to onclick by returning !!elem.onclick (or something similar).

Solution 2

I did something like that:

const element = document.getElementById('div');

if (element.getAttribute('listener') !== 'true') {
     element.addEventListener('click', function (e) {
         const elementClicked = e.target;
         elementClicked.setAttribute('listener', 'true');
         console.log('event has been attached');
    });
}

Creating a special attribute for an element when the listener is attached and then checking if it exists.

Solution 3

What I would do is create a Boolean outside your function that starts out as FALSE and gets set to TRUE when you attach the event. This would serve as some sort of flag for you before you attach the event again. Here's an example of the idea.

// initial load
var attached = false;

// this will only execute code once
doSomething = function()
{
 if (!attached)
 {
  attached = true;
  //code
 }
} 

//attach your function with change event
window.onload = function()
{
 var txtbox = document.getElementById('textboxID');

 if (window.addEventListener)
 {
  txtbox.addEventListener('change', doSomething, false);
 }
 else if(window.attachEvent)
 {
  txtbox.attachEvent('onchange', doSomething);
 }
}

Solution 4

Possible duplicate: Check if an element has event listener on it. No jQuery Please find my answer there.

Basically here is the trick for Chromium (Chrome) browser:

getEventListeners(document.querySelector('your-element-selector'));

Solution 5

tl;dr: No, you cannot do this in any natively supported way.


The only way I know to achieve this would be to create a custom storage object where you keep a record of the listeners added. Something along the following lines:

/* Create a storage object. */
var CustomEventStorage = [];

Step 1: First, you will need a function that can traverse the storage object and return the record of an element given the element (or false).

/* The function that finds a record in the storage by a given element. */
function findRecordByElement (element) {
    /* Iterate over every entry in the storage object. */
    for (var index = 0, length = CustomEventStorage.length; index < length; index++) {
        /* Cache the record. */
        var record = CustomEventStorage[index];

        /* Check whether the given element exists. */
        if (element == record.element) {
            /* Return the record. */
            return record;
        }
    }

    /* Return false by default. */
    return false;
}

Step 2: Then, you will need a function that can add an event listener but also insert the listener to the storage object.

/* The function that adds an event listener, while storing it in the storage object. */
function insertListener (element, event, listener, options) {
    /* Use the element given to retrieve the record. */
    var record = findRecordByElement(element);

    /* Check whether any record was found. */
    if (record) {
        /* Normalise the event of the listeners object, in case it doesn't exist. */
        record.listeners[event] = record.listeners[event] || [];
    }
    else {
        /* Create an object to insert into the storage object. */
        record = {
            element: element,
            listeners: {}
        };

        /* Create an array for event in the record. */
        record.listeners[event] = [];

        /* Insert the record in the storage. */
        CustomEventStorage.push(record);
    }

    /* Insert the listener to the event array. */
    record.listeners[event].push(listener);

    /* Add the event listener to the element. */
    element.addEventListener(event, listener, options);
}

Step 3: As regards the actual requirement of your question, you will need the following function to check whether an element has been added an event listener for a specified event.

/* The function that checks whether an event listener is set for a given event. */
function listenerExists (element, event, listener) {
    /* Use the element given to retrieve the record. */
    var record = findRecordByElement(element);

    /* Check whether a record was found & if an event array exists for the given event. */
    if (record && event in record.listeners) {
        /* Return whether the given listener exists. */
        return !!~record.listeners[event].indexOf(listener);
    }

    /* Return false by default. */
    return false;
}

Step 4: Finally, you will need a function that can delete a listener from the storage object.

/* The function that removes a listener from a given element & its storage record. */
function removeListener (element, event, listener, options) {
    /* Use the element given to retrieve the record. */
    var record = findRecordByElement(element);

    /* Check whether any record was found and, if found, whether the event exists. */
    if (record && event in record.listeners) {
        /* Cache the index of the listener inside the event array. */
        var index = record.listeners[event].indexOf(listener);

        /* Check whether listener is not -1. */
        if (~index) {
            /* Delete the listener from the event array. */
            record.listeners[event].splice(index, 1);
        }

        /* Check whether the event array is empty or not. */
        if (!record.listeners[event].length) {
            /* Delete the event array. */
            delete record.listeners[event];
        }
    }

    /* Add the event listener to the element. */
    element.removeEventListener(event, listener, options);
}

Snippet:

window.onload = function () {
  var
    /* Cache the test element. */
    element = document.getElementById("test"),

    /* Create an event listener. */
    listener = function (e) {
      console.log(e.type + "triggered!");
    };

  /* Insert the listener to the element. */
  insertListener(element, "mouseover", listener);

  /* Log whether the listener exists. */
  console.log(listenerExists(element, "mouseover", listener));

  /* Remove the listener from the element. */
  removeListener(element, "mouseover", listener);

  /* Log whether the listener exists. */
  console.log(listenerExists(element, "mouseover", listener));
};
<!-- Include the Custom Event Storage file -->
<script src = "https://cdn.rawgit.com/angelpolitis/custom-event-storage/master/main.js"></script>

<!-- A Test HTML element -->
<div id = "test" style = "background:#000; height:50px; width: 50px"></div>

Although more than 5 years have passed since the OP posted the question, I believe people who stumble upon it in the future will benefit from this answer, so feel free to make suggestions or improvements to it. 😊

Share:
263,709

Related videos on Youtube

Stano
Author by

Stano

Updated on July 21, 2022

Comments

  • Stano
    Stano almost 2 years

    Here is my problem: is it somehow possible to check for the existence of a dynamically attached event listener? Or how can I check the status of the "onclick" (?) property in the DOM? I have searched the internet just like Stack Overflow for a solution, but no luck. Here is my html:

    <a id="link1" onclick="linkclick(event)"> link 1 </a>
    <a id="link2"> link 2 </a> <!-- without inline onclick handler -->
    

    Then in Javascript I attach a dynamically created event listener to the 2nd link:

    document.getElementById('link2').addEventListener('click', linkclick, false);
    

    The code runs well, but all my attempts to detect that attached listener fail:

    // test for #link2 - dynamically created eventlistener
    alert(elem.onclick); // null
    alert(elem.hasAttribute('onclick')); // false
    alert(elem.click); // function click(){[native code]} // btw, what's this?
    

    jsFiddle is here. If you click "Add onclick for 2" and then "[link 2]", the event fires well, but the "Test link 2" always reports false. Can somebody help?

    • Ivan
      Ivan almost 12 years
      I'm sorry to say, but it is impossible to get the event bindings using your current method: stackoverflow.com/questions/5296858/…
    • arufian
      arufian over 7 years
      you can do it using chrome dev tool: stackoverflow.com/a/41137585/863115
    • Angel Politis
      Angel Politis over 6 years
      You can do it by creating your own storage that keeps track of the listeners. See my answer for more.
    • Syknapse
      Syknapse over 4 years
      If the objective is to prevent an event that has already been added from being added again then the right answer is here. Basically, if you use a named function instead of an anonymous one, duplicate identical event listeners will be discarded and you don't need to worry about them.
    • Jacksonkr
      Jacksonkr over 4 years
      If you're concerned about having duplicate listeners then remove the current event listener before you add it again. It's not perfect but it's simple.
  • Justin
    Justin over 9 years
    You could also assign a property to the element your element basically marking it as element that has a event attached to it;
  • Zach Saucier
    Zach Saucier almost 8 years
    onclick is separate from .addEventListener - it affects an attribute while .addEventListener does not
  • conrad10781
    conrad10781 over 6 years
    This is the approach I have used in the past. My recommendation would be to use a very specific syntax structure. IE instead of "listener", use the event itself. So "data-event-click". This provides some flexibility in the event you're looking to do more than one event, and keeps things a bit more readable.
  • user202729
    user202729 over 5 years
    This requires you to change the code of the attached event to keep track of whether it is attached (similar to this or this answer). It won't work if you don't control the code.
  • Arye Eidelman
    Arye Eidelman almost 5 years
    This with @conrad10781 's addition seems like the most reliable and simplest way. If for any reason the element is rerenderd and the event listener gets disconnected, this attribute will be reset as well.
  • Panu Logic
    Panu Logic over 4 years
    That's a good trick, but I assume it works only if you have a ref to the function that is one of the currently "added" event-listeners. I think this is clearly a shortcoming of the standard API, if we can add any event-listener, it should also be possible to check what event-listeners have been so far added. It is almost like event-listeners currently are "write only variables" which seems like an obscure concept.
  • JPA
    JPA over 4 years
    Thank you for this solution, it's straightforward and sturdy. One remark though, there is one little mistake. The function "removeListener" checks if the event array is empty or not but the ternary is incorrect. It should say "if (record.listeners[event].length!=-1)".
  • JohnK
    JohnK about 4 years
    More precisely, here: stackoverflow.com/a/41137585/1431728.
  • ceckenrode
    ceckenrode about 3 years
    In my usecase the user might have the same page open with different tabs. This only works if the event will only ever be attached in one place in one tab. The boolean can't really be kept in sync with whether or not the event is attached or not because we're just guessing that it's not when this loads
  • Devin Rhode
    Devin Rhode about 3 years
    I'd love to look at this chrome extension! I think we may have the same idea
  • Mike Gashler
    Mike Gashler about 3 years
    Alas, I built that for work so the creative portion is not mine, but I tried to share all the technical bits above.
  • Dazed
    Dazed over 2 years
    I may be going daft (74 upvotes on this) but I'm thinking that elementClicked.setAttribute('listener', 'true'); should be added outside the addEventListender function - otherwise it is only added when the event is triggered and therefore doesn't actually allow you to check the event listener is attached reliably.
  • Dazed
    Dazed over 2 years
    At time of posting this is top voted, but (as above comment) the logic is a little off. A better alternative is below (stackoverflow.com/a/69189193/1265200)
  • Dazed
    Dazed over 2 years
    only one suggestion - the element.setAttribute('listenerOnClick', 'true'); could/should be inside the if
  • minigeek
    minigeek about 2 years
    I wrote utility method stackoverflow.com/a/71247657/6789999