0

I'm writing a userscript to reformat a table, and I'm running into something I don't understand. The short version is that when I ask for the lastChild of a element, I get text, not the last in the row, as I'd expect. Am I using lastChild wrong?

The html looks like this:

<tbody id="questions">
  <tr class="drag-row" id="drag-row-4819" style="cursor: auto; left: 268.34375px;">
    <td style="background-color: #eee; text-align: center; ;"><small class="muted">Page 1</small></td>
    <td style="width:15px;"></td>
    <td class="text-right" style="width:35px;">1</td>
    <td>Do you want to fill out the priority list?</td>
    <td style="width:150px;">Multiple choice (only one answer)</td>
    <td>
      <a href="/customers/4/accounts/2/portals/211/forums/Forum_577/issues/Issue_2797/survey_questions/4819">Edit</a>
      <a data-confirm="WARNING: Are you sure you want to delete this question?" data-method="delete" href="/customers/4/accounts/2/portals/211/forums/Forum_577/issues/Issue_2797/survey_questions/4819" rel="nofollow">Delete</a>
    </td>
  </tr>
  etc., more <tr/> elements here

I'm trying to separate the "Delete" link from the last element in each row into a new element at the end of each row.

My userscript code, which WORKS, is this.

var rows = document.getElementById("questions").children,
  separateDeleteLink = function(row) {
    var deleteCell = row.children[row.children.length - 1];
    if (deleteCell.children.length == 2) {
      var deleteLink = deleteCell.children[1];
      console.log(deleteLink);
      row.appendChild(document.createElement("td")).appendChild(deleteLink);
    }
  };

[].forEach.call(rows, separateDeleteLink);

For some lines, for example var deleteCell = row.children[row.children.length - 1], I'd really prefer to write var deleteCell = row.lastChild. But when I do that, it doesn't work. console.log(row.lastChild) returns an object called #text.

By the way, I'm new to Javascript, so I appreciate any style or other tips on my code. But first, what's going on with lastChild?

Nicholas Barry
  • 558
  • 2
  • 5
  • 15
  • lastChild is a node object, whereas children returns elements. Check out this questions here http://stackoverflow.com/questions/7935689/what-is-the-difference-between-children-and-childnodes-in-javascript – TommyBs Jul 14 '15 at 07:26

2 Answers2

1

You are looking for row.lastElementChild.

Notice that DOM is composed from nodes. Nodes are not just elements, but also spaces, texts and other junk that you might not want to work with.

Entity Black
  • 3,401
  • 2
  • 23
  • 38
  • PS: browser support: https://developer.mozilla.org/cs/docs/Web/API/ParentNode/lastElementChild#Browser_compatibility – Entity Black Jul 14 '15 at 07:35
0

What you're missing is that the fact that your source code is nice and indented and human readable causes you to have all these text nodes in your DOM for all those tabs and newline characters in between the tags.

That is why .lastChild() returns you a text node - it is literally the last node before the closing </tr> tag.

Just in case you were wondering, this isn't reason enough to remove the pretty formatting. You just need to code around it using something like .lastElementChild as @Entity Black suggested, or .children[x.children.length - 1] as you have been doing to make sure you get only an element, not a node.

GregL
  • 37,147
  • 8
  • 62
  • 67