1

I have a page (actually, about thirty or so) where I'm trying to change the classname of specific elements based on a querystring variable. Everything works fine except for this part, I'm getting a really weird result...

        var hitAreas = document.getElementsByClassName('hitArea');
    alert(hitAreas.length);
    for(hitArea in hitAreas)
    {
        alert(hitAreas[hitArea]);
        hitAreas[hitArea].className = 'hitArea_practice';
    }

The alert(hitAreas.length); line is properly returning the number of elements (7, from the html below) with the classname 'hitArea', but when I iterate through hitAreas, it's only changing the classnames for every other element on the page. Halfway through it returns undefined as a value for alert(hitAreas[hitArea]); assumably because it's trying to reference array elements beyond an index of 6.

Body of the html page:

        <body onload="toggleHotspotHints();">
<div>
    <img src="Dashboard1.jpg" width="1440" height="795" />
    <div class="hitArea" style="top: 55px; left: 230px; width: 72px; height: 17px;" onclick="gotoPage('BatchReconcile/1-ClaimsReconcileMenu');"></div>
    <div class="hitArea" style="top: 55px; left: 319px; width: 72px; height: 17px;" onclick="gotoPage('Eligibility/PP Elig 1');"></div>
    <div class="hitArea" style="top: 55px; left: 409px; width: 72px; height: 17px;" onclick="gotoPage('REPORTS/5-Dashboard Reports List');"></div>
    <div class="hitArea" style="top: 137px; left: 260px; width: 145px; height: 21px;" onclick="gotoPage('Dash2_Messages');"></div>
    <div class="hitArea" style="top: 223px; left: 247px; width: 126px; height: 19px;" onclick="gotoPage('ClaimsList_Failed');"></div>
    <div class="hitArea" style="top: 242px; left: 247px; width: 126px; height: 14px;" onclick="gotoPage('PayerReportList');"></div>
    <div class="hitArea" style="top: 258px; left: 247px; width: 126px; height: 14px;" onclick="gotoPage('ADM/1_trending graph');"></div>
</div>

Live demo: http://jsfiddle.net/simevidas/LE6UN/

Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
Eric
  • 2,061
  • 8
  • 28
  • 37

1 Answers1

3

Šime Vidas pointed out that getElementsByClassName retuns a live nodeList, meaning the collection stored will be updated as things are changed (here the class attribute).

var hitAreas = document.getElementsByClassName('hitArea'),
    hitAreasLength = hitAreas.length;

while ( hitAreasLength-- > 0) {
    hitAreas[hitAreasLength].className = 'hitArea_practice';
}

I'm not sure if this is the nicest code, but it works :)

jsFiddle.

Community
  • 1
  • 1
alex
  • 479,566
  • 201
  • 878
  • 984
  • @alex This doesn't answer the question. The question is: Why doesn't the for...in loop iterate over all the DIV, but only every other DIV? – Šime Vidas Mar 03 '11 at 23:40
  • @ime Vidas The normal `for` loop does as well, and I'm stumped. Only by using other methods of selecting was I able to get normal behaviour. – alex Mar 03 '11 at 23:43
  • @alex getElementsByClassName doesn't work, querySelectorAll does work. It may be because one of those is a live NodeList while the other one isn't. (I am not sure if that is true, and if yes, which one is which, but that could explain it.) – Šime Vidas Mar 03 '11 at 23:51
  • @alex getElementsByClassName is a [live NodeList](https://developer.mozilla.org/en/DOM/document.getElementsByClassName). querySelectorAll is a [non-live NodeList](https://developer.mozilla.org/En/DOM/Document.querySelectorAll). I think that is the cause of this issue. – Šime Vidas Mar 03 '11 at 23:53
  • @Sime Vidas Thanks, I'll look into that (and apologies, the script I was using to add reply name skipped over the Š in your name earlier). – alex Mar 03 '11 at 23:58
  • @Šime Vidas I updated my answer and this one works. Cheers for pointing that out, I didn't even think of it. – alex Mar 04 '11 at 00:06
  • Live lists can catch you off guard, but they're slick. You could actually forget the `length` and just do this: `while ( hitAreas[0] ) { hitAreas[0].className = 'hitArea_practice'; }` Since you're entirely changing the `className` of all the elements, the one at index `[0]` is being removed from the list in each iteration. – user113716 Mar 04 '11 at 00:13
  • @patrick dw Thanks Patrick, this is the first time I've came across one (usually I am using jQuery) so it did indeed catch me off guard! I'll remember that syntax for the future, cheers. – alex Mar 04 '11 at 00:19
  • Thanks, guys. This worked like a breeze! I must admit that I'm a bit behind on my JS chops, so I'm usually falling back on older hooks. – Eric Mar 04 '11 at 15:06