Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript only last event listener works

It's very difficult for me to show you my code, as it's all over the place, but what I'm trying to do is this:

I am injecting html code into the DOM in a function buy using .innerHTML, I wish to add a click event to an icon that is being injected in this step, as at this moment in time I know its id. So after I've injected it I write:

document.getElementById(product.id+"x").addEventListener("click", removeItem);

product.id is created above and this element is a 'X' button, that when clicked will be removed from the screen.

The trouble is, this code is run many times as there are many items to be displayed on the screen. And when finished, only the last even made fires when the 'X' button is pressed.

Any suggestions?

EDIT:

I am unable to use jquery in this project.

Here is my code:

function createHTML(targetID, product) {
    var target = document.getElementById(targetID);
    total = (parseFloat(total) + parseFloat(product.price)).toFixed(2);;
    target.innerHTML += '<article class="item" id="'+product.id+'"><img class="item_img" src="../'+product.image+'" width=100 height=100><h1 class="item_name">'+product.name+'</h1><p class="item_description">'+product.desc+'</p><h1 class="item_quantity">Quantity: '+product.quantity+'</h1><h1 class="item_price">&pound;'+product.price+'</h1><i id="'+product.id+'x" class="fa fa-times"></i></article>';

    document.getElementById(product.id+"x").addEventListener("click", removeItem, true);
}
like image 595
benharris Avatar asked Apr 11 '14 13:04

benharris


People also ask

How do you make an event listener only work once?

We can pass an object as an argument to the addEventListener method and specify that the event is only handled once. This is achieved by passing the property once to the object. If we set once to true, the event will only be fired once.

How does event listener work in Javascript?

Event listeners are called only when the event happens in the context of the object they are registered on. That example attaches a handler to the button node. Clicks on the button cause that handler to run, but clicks on the rest of the document do not. Giving a node an onclick attribute has a similar effect.

How do I remove event listener in react?

Add the event listener in the useEffect hook. Return a function from the useEffect hook. Use the removeEventListener method to remove the event listener when the component unmounts.


2 Answers

So you're adding new elements to a container by overwriting the innerHTML or appending to it using +=. This is your problem. When you overwrite the innerHTML or append to it, you are destroying and recreating all elements within it and this causes them to lose any bound event handlers (ie your click handler).

This fiddle reproduces your problem. Only the last button has a click handler.

The solution is to build DOM elements using document.createElement() and use appendChild() or similar to append them, instead of creating/appending raw HTML. This way, your previous elements event handlers will remain intact.

This Fiddle uses DOM nodes instead of raw HTML and all buttons have a click handler.

Example fix:

var container = document.getElementById("container");
var elem;

function clicky(){
    alert("clicked");   
}

for(var i=0; i<4; i++){
    elem = document.createElement('button');
    elem.id = "btn_" + i;
    elem.appendChild(document.createTextNode('Click'));
    elem.addEventListener("click", clicky);
    container.appendChild(elem);
}
like image 52
MrCode Avatar answered Nov 02 '22 07:11

MrCode


I quess you do something like that

//Place where you add elements.
var container = document.body;

you create element and add listener to that element(button):

var button = '<button id="btn1x">Button 1</button>';
container.innerHTML += button;

//product.id = 'btn1';
document.getElementById(product.id+"x").addEventListener("click", removeItem);

and then you add in the same way new elements and add for them event listeners before next element will be generated.

If my quess is right, then your problem is that you replace whole content of container so previous event listens are lost.

stringVariable += 'abc' is the same as stringVariable = stringVariable + 'abc'. Because of that you overwrite html.

You should create elements from functions, not from string as you do now.

var button = document.createElement('button');
button.id = product.id + 'x'; 
button.innerText = 'Button 1'; // Title of button.

//Add button to container.
container.appendChild(button);

//Add event listener to created button.
button.addEventListener('click', myFunc); 

UPDATE:

There are a way to parse your string to element.

First create container where will be set inner html from string, then get from that temp container first element (or more elements, depends from your html string), then add them to container and add to these elements listeners.

DEMO: http://jsfiddle.net/3cD4G/1/

HTML:

<div id="container">

</div>

Javascript:

var container = document.getElementById("container");

function clicky(){
    alert("clicked");   
}
var tempContainer = document.createElement('div');
for(var i=0; i<4; i++){
    //Create your element as string.
    var strElem = "<button type='button' id='btn_" + i + "'>Click</button>";
    //Add that string to temp container (his html will be replaced, not added).
    tempContainer.innerHTML = strElem.trim();//Trim function used to prevent empty textnodes before element.
    //Get element from temp container.
    var button = tempContainer.children[0];
    //Empty tempContainer for better security (But about which security I'm talking in JavaScript in string element generation :) )
    tempContainer.innerHTML = '';

    //Add your button to container.
    container.appendChild(button);

    //Add event listener to button:
    //document.getElementById("btn_" + i).onclick = clicky;
    //Better way to add event listener:
    button.addEventListener('click', clicky);
}

DEMO: http://jsfiddle.net/3cD4G/1/

like image 27
Epsil0neR Avatar answered Nov 02 '22 07:11

Epsil0neR