Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

getElementsByTagName out of synch with innerHTML #11

Open
orslumen opened this issue Mar 18, 2011 · 1 comment
Open

getElementsByTagName out of synch with innerHTML #11

orslumen opened this issue Mar 18, 2011 · 1 comment

Comments

@orslumen
Copy link

One of my jQuery plugins uses the $.wrap() function. After that method is called, the getElementsByTagName function returns incorrect results. It completely ignores the new element and moves the wrapped element to the end of the list.

To reproduce (without jQuery):

<html lang='en-US' xml:lang='en-US' xmlns='http://www.w3.org/1999/xhtml'>
  <head/>
  <body>
    #container
      #before
      #to_be_wrapped
      #after
    <script type="text/javascript">
      //<![CDATA[
        // Print the current state to the console, this is OK
        var container = document.getElementById('container');
        console.log('\r\nBefore:\r\n'+container.innerHTML);
        var all = container.getElementsByTagName('*'); var ids = ''; for(var i=0; i < all.length; i++) { ids = ids + (String.isBlank(ids) ? '' : ', ') + all[i].getAttribute('ID'); } console.log('getElementsByTagName("*") returns%selements:%s', all.length, ids);

        // Wrap the #to_be_wrapped node in a new #wrapper node
        var wrapper = document.createElement('div');
        wrapper.id = "wrapper";
        var to_be_wrapped = document.getElementById('to_be_wrapped');
        container.insertBefore(wrapper, to_be_wrapped);
        wrapper.appendChild(to_be_wrapped);

        // Print the results of the incorrect state of getElementsByTagName
        console.log('\r\nAfter:\r\n'+container.innerHTML);
        all = container.getElementsByTagName('*'); ids = ''; for(var i=0; i < all.length; i++) { ids = ids + (String.isBlank(ids) ? '' : ', ') + all[i].getAttribute('ID'); } console.log('getElementsByTagName("*") returns%selements:%s', all.length, ids); 

        // Show that childNodes still reflects the correct state
        all = container.childNodes; ids = ''; var id_count = 0; for(var i=0; i < all.length; i++) { if (all[i].nodeType == Node.ELEMENT_NODE) { id_count++; ids = ids + (String.isBlank(ids) ? '' : ', ') + all[i].getAttribute('ID'); } } console.log('childNodes returns%selements:%s', id_count, ids); 
      //]]>
    </script>
  </body>
</html>

This produces the following results:
Before:

<div id="before"/>
<div id="to_be_wrapped"/>
<div id="after"/>
getElementsByTagName("*") returns 3 elements: before, to_be_wrapped, after 

After:

<div id="before"/>
<div id="wrapper"><div id="to_be_wrapped"/></div>
<div id="after"/>
getElementsByTagName("*") returns 3 elements: before, after, to_be_wrapped 
childNodes returns 3 elements: before, wrapper, after 

As you can see the innerHTML is correct, but the container.getElementsByTagName("*") is missing the #wrapper div and has incorrectly moved the #to_be_wrapped div to the end.

Fortunately the childNodes property does contain the correct state, so as a workaround I switched back to the old recursive implementation of getElementsByTagName using childNodes, which seems to work fine for the moment.

@mauricioszabo
Copy link

I'm having a different problem: I have a HTML file like the following:

 <script language="javascript">
     document.getElementById('ex').innerHTML = '\
 <table class="table">\
   <tr>\
       <th class="sorting"><a href="#">login</a></th>\
   </tr>\
 </table>';
 </script>

It just replaces an innerHTML of a div with some data. After loading this page:

console.log("Link elements: " + document.getElementsByTagName("a").length);

This shows me "Link elements: 0", which is wrong - expected to be 1. However, if I try:

var elements = [];
var all = document.getElementsByTagName("*");
for(var i = 0; i < all.length; i++) {
    if(all[i].tagName === 'A') {
        elements.push(all[i]);
    }
}
console.log("Link elements filtered: " + elements.length);

It gives me the correct number of elements (in this case, 1).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants