What causes this unexpected javascript error?

This code is intended to add a "display: none" style to every element that does not have a "ShowThis" class or a descendant with this class:

var x = document.getElementsByTagName('*'); for(var i = x.length; i--;){ x[i].style.display = 'none'; if((' '+x[i].className+' ').indexOf(' ShowThis ') >= 0){ var y = x[i]; while(y){ if(y.nodeType === 1){ console.log(y.style.cssText); // Outputs: "display: none;" console.log(y.style.display); // Outputs: "none" y.style.display = 'block'; console.log(y.style.display); // Outputs: "block" console.log(y.style.cssText); // Outputs: "display: block;" // ERROR here: // Outputs the elements HTML (Chrome Console), // But the style attribute isn't changed // EX. <div style="display: none;">...</div> console.log(y); } y = y.parentNode; } } } 

Here's the JSFiddle: http://jsfiddle.net/Paulpro/wEq8X/

It works fine if you comment out if(y.nodeType === 1){ and match } ( http://jsfiddle.net/Paulpro/wEq8X/1/ ), or if I changed the if if(y.nodeType) or if(true) , which does not make any sense to me at all, because the program stream introduces this if statement (all console.log are executed) anyway.

I tried changing the if statement to if(typeof y.style !== 'undefined') and it is behaving incorrectly. (Exactly the same problem)

I need to test a nodeType or style to prevent an error while trying to access a document style property, but testing any of them gives me this weird behavior.

I can reproduce this in Chrome, Firefox and IE.

+4
source share
2 answers

Your code sets the containing block to display: none. After that, it doesn't matter that the internal <div> is "display: block".

Your diagnostic item reset technique is erroneous. If you use something like a Chrome or Firebug debugger, you will see that your “ShowThis” element really has “display: block” in its “style” attribute. However, it is not displayed because all of its parent elements (including the <body> ) are still "display: none".

edit I think the problem is probably related to the order in which page elements are displayed as a result of "getElementsByTagName ()". If you reach the parent after the children, then they will be set to "display: none" after they are set to "display: block".

change again - confirmed. Elements are returned from "getElementsByTagName ()" in the reverse order that they appear in HTML. So the last element that your code sees in the outer loop is the <div> container for the "ShowThis" <div> .

edit again, oh, I see - you're coming back! Durr. If you go through the node list, it should work.

+2
source

You indicate that your outer loop that hides everything will hide the parent rollers of the 'showthis' node after you set to display = 'block'. If you separate the hiding and showing in two steps, it works great.

 var y, x = document.getElementsByTagName('*'); for(var i = 0, len = x.length; i < len; i++){ x[i].style.display = 'none'; } x = document.getElementsByClassName('ShowThis'); for(var i = 0, len = x.length; i < len; i++) { y = x[i]; while(y){ if(y.nodeType === 1){ y.style.display = 'block'; } y = y.parentNode; } } 

Also, just for the record, this type of thing is where jQuery is awesome.

 jQuery('*').hide(); jQuery('.ShowThis').show().parents().show(); 
+1
source

All Articles