3

I'm trying to add inner html to div element, and then add click event to it dynamically. It alerts 1 but not 2:

alert(wordsGeneral.length); //prints 9
for (var i = 0; i < wordsGeneral.length; i++)
{
    var word = wordsGeneral[i];
    if (wordsToCorrect[word]!= undefined)
    {

        document.getElementById("text").innerHTML += "<u id=\"" + i + "\" style=\"text-decoration: underline;text-decoration-color: red;\">" + word + "</u>";
        alert("1");
        document.getElementById(i).addEventListener("click", function () {
            alert("2");
        });
    }
}

Can someone help?

3
  • 2
    What is i? Can you post more of your code? Commented May 7, 2018 at 20:44
  • I think I know what the issue is but I don't want to post an answer until I'm sure, can you edit your question to show how i is defined and used? Commented May 7, 2018 at 22:26
  • I've just edited this. Can you please tell what have you think about? Commented May 8, 2018 at 0:36

2 Answers 2

3

Seems to work just fine:

i = 1;
word = i;
document.getElementById("text").innerHTML += "<u id=\""+i+"\" style=\"text-decoration: underline;text-decoration-color: red;\">" + word + "</u>";
alert("1");
document.getElementById(i).addEventListener("click", function () {
    alert("2");
});
<div id="text"/>

I would guess that you are not using HTML5, and that i is a number, which in HTML4 is not valid:

ID and NAME tokens must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").

Sign up to request clarification or add additional context in comments.

2 Comments

This seems to be the most logical answer with the little information given by the OP.
Thanks, but even tough I change the id to AAA in both lines, it doesn't work. BTW var word is "name" for instance.
0

Every time you assign to the innerHTML of a container, any Javascript references to elements inside the container are destroyed. When you do something.innerHTML +=, the interpreter does something like:

(1) Retrieves the current innerHTML of the container as a string

(2) Clears the container's contents

(3) Concatenates the string with whatever you added

(4) Assigns to the container's innerHTML with the new string

So if you have an element inside the container and you assign it an event listener, if you ever assign (or concatenate to) the container's innerHTML, the listener will be lost; the whole internal structure of the container will be re-parsed from scratch from the HTML string.

There are at least two good solutions to this sort of thing:

  • Don't append HTML strings, especially when dealing with user input. Instead, create elements and append them to the container:

const text = document.querySelector('#text');
const wordsGeneral = ['foo', 'bar', 'baz'];
for (let i = 0; i < wordsGeneral.length; i++) {
  const word = wordsGeneral[i];
  text.insertAdjacentHTML('beforeend', "<u id=\"" + i + "\" style=\"text-decoration: underline;text-decoration-color: red;\">" + word + "</u>");
  document.getElementById(i).addEventListener("click", function() {
    alert("2");
  });
}
<div id="text"></div>

Another method is to use the appendAdjacentHTML method, which is designed for this sort of thing and does not dereference other elements in the container:

const text = document.querySelector('#text');
const wordsGeneral = ['foo', 'bar', 'baz'];
for (let i = 0; i < wordsGeneral.length; i++) {
  var word = wordsGeneral[i];
  const u = text.appendChild(document.createElement('u'));
  u.id = i;
  u.style.cssText = 'text-decoration: underline;text-decoration-color: red;';
  u.textContent = word;
  u.addEventListener("click", function() {
    alert("2");
  });
}
<div id="text"></div>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.