Search code examples
javascriptjqueryinternet-explorerdomnormalize

IE11 DOM normalize doesn't work with table row


I'd like to normalize table rows. This works like a charm, except in IE (tested with IE 11).

I've created a demo snippet to demonstrate the issue:

$(function() {
  $("table tbody tr span").each(function() {
    var $this = $(this);
    var $parent = $this.parent();
    $this.replaceWith($this.html());
    $parent[0].normalize();
  });
});
<link href="https://cdn.jsdelivr.net/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="table table-striped table-hover">
  <thead>
    <tr>
      <th>President</th>
      <th>Birthplace</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><span>Zach</span>ary Taylor</td>
      <td>Barboursville, Virginia</td>
    </tr>
  </tbody>
</table>

This replaces the <span> element with its content. After this step the node will look like:

DOM Node

Then, normalize() is called to merge the splitted text nodes. However, in IE11 the text nodes are still splitted.

I can't see any issue from my side. What's the cause of this problem and what could be the solution?


As it turned out that this is a IE11 bug, I've filled in a bug report!


Solution

  • It seems like IE-11 can't normalize elements that are already part of your document If your developers toolbar is open.

    This is also relevant for IE9 & 10 (emulated by using meta http-equiv="X-UA-Compatible" tag)

    When you only create new nodes and you don't attach them to the document - everything works great (for both situations - developers toolbar is open and close):

    d = document.createElement('div');
    d.appendChild(document.createTextNode('text 1'));
    d.appendChild(document.createTextNode('text 2'));
    console.log(d.childNodes.length + ' - Should be 2')
    d.normalize();
    console.log(d.childNodes.length + ' - Should be 1')

    If, however, you are working with nodes that are already part of your document, the normalize function doesn't work if your developer toolbar is open:

    d = document.getElementsByTagName('div')[0];
    d.appendChild(document.createTextNode('text 1'));
    d.appendChild(document.createTextNode('text 2'));
    console.log(d.childNodes.length + ' - should be 2 on every browser')
    d.normalize();
    console.log(d.childNodes.length + ' - should be 1, however it\'s 2 on IE')
    <div></div>

    If you really want, what you can do is extract the nodes from the document and add them after you normalize them:

    d = document.getElementsByTagName('div')[0];
    d.appendChild(document.createTextNode('text 1'));
    d.appendChild(document.createTextNode('text 2'));
    console.log(d.childNodes.length + ' - should be 2 on every browser')
    
    dNew = d.cloneNode(true)
    dNew.normalize()
    d.parentElement.replaceChild(dNew, d)
    
    d = document.getElementsByTagName('div')[0];
    console.log(d.childNodes.length + ' - should be 1 on every browser')
    <div></div>

    Update - 28/8
    Answer was updated after the comment from @dude. It took some time to investigate the cause here, but I think that now I covered everything.

    Note that for IE8 (forced by using <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8"> in IE-11) the normalize() function works for both elements that are in the DOM tree and elements that are not, even with the developers toolbar was open.