T.Poe
T.Poe

Reputation: 2089

Javascript: event.target.id undefined in event listener

I'm trying to add event listeners for multiple divs in a for loop:

var divElements = document.getElementsByClassName('B');
var vMax = divElements.length;
for (var i = 0; i < vMax; i += 1) {
    divElements[i].addEventListener('DOMCharacterDataModified', function(e) {
        myFunc(e.target);
    }, false);
}

function myFunc(elem) {
    var text = elem.textContent;
    var id = elem.id;
    console.log("text: " + text);
    console.log("id: " + id);
}

Problem with this code is, that although the text is OK and correct text is in it, id variable is undefined, although the element has id set in html. Is this code OK or am I missing something?

I also tried e.target.getAttribute("id") but it ends up with e.target.getAttribute is not a function error.

Upvotes: 1

Views: 3838

Answers (2)

Scott Marcus
Scott Marcus

Reputation: 65815

The issue is that a text node is node that is created as an implicit child node of most element nodes. You are trying to get the id of the parent element node of the text node in question, but elem is a child of that node, so you have to access elem.parentNode.id.

We can see this by examining the nodeType and nodeName properties of the different nodes.

From MDN:

  • Element Nodes have a node type of 1
  • Text Nodes have a node type of 3

var div = document.getElementById("A");
div.addEventListener('DOMCharacterDataModified', function(e) {
  console.log("Target element is a " + e.target.nodeName + " node and has a node type of: " + e.target.nodeType);
  console.log("Target element.parentNode is a " + e.target.parentNode.nodeName + 
               " node and has a node type of: " + e.target.parentNode.nodeType);

  console.log("Target element.text: " + e.target.textContent);
  console.log("Target element.parentNode.id: " + e.target.parentNode.id);
});
<h1>Click into the text below and modify it somehow:</h1>
<div id="A" contenteditable>Something</div>

Upvotes: 1

James
James

Reputation: 22247

It looks like you want the parameter being passed into myFunc to be the div that you are assigning the handler to, so just replace e.target with this in the function call.

var divElements = document.getElementsByClassName('B');
var vMax = divElements.length;
for (var i = 0; i < vMax; i += 1) {
    divElements[i].addEventListener(
      'DOMCharacterDataModified', 
      function(e) {
        myFunc(this);
      },
      false
    );
}

function myFunc(elem) {
    var text = elem.textContent;
    var id = elem.id;
    console.log("text: " + text);
    console.log("id: " + id);
}
<div class='B' id='p1' contenteditable>part 1</div>
<div class='B' id='p2' contenteditable>part 2</div>
<div class='B' id='p3' contenteditable>part 3</div>

Upvotes: 0

Related Questions