最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Get element event listener and store it - Stack Overflow

programmeradmin0浏览0评论

I want to remove an event listener from an element and later assign it back. Is there a way to get it and store in a variable smth like var storedListener = Element.getEventListener('click'), so that later I can do something like Element.addEventListener('click', storedListener)?

UPDATE

Listener is assigned inside template, I use Angular 2. It's

<div *ngFor="let entry of data; let i=index">
  <div class="element-description" (click)="editElementDescription(i)">{{entry.description}}</div>
</div>

What I want to do is to make contents of inside <div> an <input> after I click it, so that I can change value and send it to server. And inside editElementDescription() I do the following:

public editElementDescription(index: number): void {
    var elementDescription: HTMLDivElement = <HTMLDivElement>document.getElementsByClassName('element-description')[index];
    elementDescription.removeEventListener('click');
    elementDescription.innerHTML = '<input id="change-description-input" type="text" value="' + elementDescription.innerHTML + '"/>';
  }

I remove that click listener because otherwise contents of <input> will get that innerHTML if I click it one more time. So the idea is to assign that <input> element a change listener, which will replace <input> by it's value and bring the parent <div> it's original listener back.

I want to remove an event listener from an element and later assign it back. Is there a way to get it and store in a variable smth like var storedListener = Element.getEventListener('click'), so that later I can do something like Element.addEventListener('click', storedListener)?

UPDATE

Listener is assigned inside template, I use Angular 2. It's

<div *ngFor="let entry of data; let i=index">
  <div class="element-description" (click)="editElementDescription(i)">{{entry.description}}</div>
</div>

What I want to do is to make contents of inside <div> an <input> after I click it, so that I can change value and send it to server. And inside editElementDescription() I do the following:

public editElementDescription(index: number): void {
    var elementDescription: HTMLDivElement = <HTMLDivElement>document.getElementsByClassName('element-description')[index];
    elementDescription.removeEventListener('click');
    elementDescription.innerHTML = '<input id="change-description-input" type="text" value="' + elementDescription.innerHTML + '"/>';
  }

I remove that click listener because otherwise contents of <input> will get that innerHTML if I click it one more time. So the idea is to assign that <input> element a change listener, which will replace <input> by it's value and bring the parent <div> it's original listener back.

Share Improve this question edited Feb 8, 2017 at 14:40 Leonid Bor asked Feb 8, 2017 at 14:05 Leonid BorLeonid Bor 2,2748 gold badges29 silver badges53 bronze badges 3
  • Your call to elementDescription.removeEventListener is invalid since this method takes 2 arguments. You need to pass a direct reference to the listener function as second argument. – lleaff Commented Feb 8, 2017 at 14:50
  • Now I got your situation (after edit). But I suggest another approach: instead of controlling your events, you can use data- attribute to control your element state. I edited my answer. – luiscrjr Commented Feb 8, 2017 at 14:59
  • Ok, i guess i'll just introduce a local variable for the ponent, which will be boolean for clicked condition and depending on that html template will show either <a> with value or <input>, controlled by *ngIf. Thx for answers! – Leonid Bor Commented Feb 8, 2017 at 15:11
Add a ment  | 

3 Answers 3

Reset to default 3

In order to remove a listener added with .addEventListener(), you must keep track of the listener function reference and remove it later with .removeEventListener().

Something like that:

var btn = document.getElementById('btn');
var btn_add = document.getElementById('btn-add-listener');
var btn_remove = document.getElementById('btn-remove-listener');

var fnListener =  function(e) {
    alert('Clicked!');
};


btn_add.addEventListener('click', function() {
    btn.addEventListener('click', fnListener);
});

btn_remove.addEventListener('click', function() {
    btn.removeEventListener('click', fnListener);
});

Working demo: https://jsfiddle/mrlew/k5m1nog3/


Other approach (added after question update)

Considering your actual problem, I suggest another approach: instead of handle events, you can set a data- attribute in the element indicating it's open. Then you just modify your inner HTML if the attribute is not present.

Something like this:

function editElementDescription(index) {

    var elementDescription = document.getElementsByClassName('element-description')[index];

    var isOpen = elementDescription.getAttribute('data-isOpen');

    if (!isOpen) {
      elementDescription.setAttribute('data-isOpen', 'true');
      elementDescription.innerHTML = '<input id="change-description-input" type="text" value="' + elementDescription.innerHTML + '"/>';

    }

}

Working demo: https://jsfiddle/mrlew/e0yrL08v/

You are getting it a bit wrong... there is no list of event listeners accessible from JavaScript... the only thing you can do is to remove/add an event if you know the origin.

There are 2 functions to manipulate event listeners:

  1. addEventListener(event_type,function);
  2. removeEventListener(event_type,function);

One object can have multiple events of same type... the only way to distinguish them is by giving an exact function being called.

Please note that if it's jQuery, it is possible, as it has own event stack... example below:

var events = $("#object1").data('events');
var $object2 = $("#object2");
if (events) {
    for(var eventType in events){
        for(var idx in events[eventType]){
            $object2[eventType](events[eventType][idx].handler);
        }
        $('#object1').off(eventType);
    }
}

No, this isn't possible since .getEventListener is only available for debugging purposes. There is unfortunately no way in standard JavaScript to programmatically get back the EventListeners attached to an object, and any library that tries to acplish this will rely on unstable non-standard interfaces that may be discontinued any day.

So if your goal was to manipulate the listeners added by a library you have no control over, you're out of luck.
On the other hand if you control the environment then you can store a reference to the attached callback if you want to attach the same listener to multiple objects, or remove it afterwards with .removeEventListener.

You could actually monkey-patch EventTarget.prototype.addEventListener to support this before anything else runs on your page, that wouldn't be a very clean solution to whatever problem you are having but if you think you really need to, here is a quick imperfect implementation of it (doesn't support useCapture argument):

// getEventListener polyfill, run this before anything else on your page.
(function monkeyPatchGetEventListeners(EventTarget) {

  const eventListeners = new WeakMap();

  const origAddEventListener = EventTarget.prototype.addEventListener;
  EventTarget.prototype.addEventListener = function patchedAddEventListener(eventType, listener, ...args) {
    let allListeners;
    if (eventListeners.has(this)) {
      allListeners = eventListeners.get(this);
    } else {
      allListeners = new Map();
      eventListeners.set(this, allListeners);
    }

    let listeners;
    if (allListeners.has(eventType)) {
      listeners = allListeners.get(eventType);
    } else {
      listeners = [];
      allListeners.set(eventType, listeners);
    }

    listeners.push(listener);
    return origAddEventListener.call(this, eventType, listener,...args);
  }

  const origRemoveEventListener = EventTarget.prototype.removeEventListener;
  EventTarget.prototype.removeEventListener = function patchedRemoveEventListener(eventType, listener, ...args) {
    const call = () => origRemoveEventListener(eventType, listener, useCapture, ...args);
    const allListeners = eventListeners.get(this);
    if (!allListeners) { return call(); }
    const listeners = allListeners.get(this);
    if (!listeners) { return call(); }
    const index = listeners.indexOf(listener);
    if (index === -1) { return call(); }
    index.splice(index, 1);
    return call();
  }

  EventTarget.prototype.getEventListeners = function patchedGetEventListeners(eventType) {
    const allListeners = eventListeners.get(this);
    return allListeners && allListeners.get(eventType);
  }
})(EventTarget);
发布评论

评论列表(0)

  1. 暂无评论