简体   繁体   中英

What's wrong with my attempt to remove an element with JavaScript?

I have a form where I use the following system: the fields and their labels are float: left and an extended comment explaining how to fill in the field appears far to the right, positioned with a wide left margin.
Following a suggestion in an Eric Meyer book, I use an hr to align the two: I put an hr styled with:

.lineup { clear:both; visibility: hidden}

Then I use Javascript to make the comment display when I want it.
This works great, except (for some weird problem in Safari and) when the comment is really long, when it "pushes down" the other form content as it appears.
So, I said, I can write a Javascript function to run on page build, to delete the hr's (remembering their offsetTop's) and move all the descriptions to somewhere near where the hr's were.
But I can't get it to remove the hr's.

Finally the code:

var hrListY = new Array();              // Y-coordinates of HR "lineup" elements

// Moves all descriptions so their middle is where the top used to be, and
// removes the <hr>s previously used to position them.

function relayoutDescriptions() {
        var hrs = document.getElementsByTagName("hr");
        alert('hrs.length = ' + hrs.length);
        var i;
        for (i = 0; i < hrs.length; i++) {
                var hr = hrs[i];
                if (hr.className == 'lineup') {
                        hrListY.push(hr.offsetTop);
                        alert('Got an HR element: Y = ' + hr.offsetTop + ' parentNode class = "' + hr.parentNode.className + '"');
                        hr.parentNode.removeChild(hr);
                        }
                }

// Now we have a list of Y-coordinates of HR elements, hrListY.  We use it
// to adjust the offsetTop's of the -desc divs.  For each one, we adjust the
// offsetTop so the center of the div is at the height where the HR was.

        }

That's all I have of it so far. It gives me reasonable ascending numbers for offsetTop, and a plausible parent node class, but the resulting layout clearly shows, and firebug confirms, that the hr's are still there.

Help?

PS
If there's an easy way to do this with JQuery, I'm amenable to that, but I'd REALLY like to know what the $@#&*% is going on here.

Thanks!

The node list returned by getElementsByTagName is live, which means that when you remove one of its elements from the DOM, the things to the right move left, so you're only removing every second item.

From http://www.w3.org/TR/DOM-Level-2-Core/core.html

NodeList and NamedNodeMap objects in the DOM are live; that is, changes to the underlying document structure are reflected in all relevant NodeList and NamedNodeMap objects.

You can see that this is so by moving the alert('hrs.length = ' + hrs.length); inside your loop. It will alert a different number each time through.

To fix this, you can copy the list

var myNodeList = document.getElementsByTagName('HR');
myNodeList = Array.prototype.slice.call(myNodeList);

or you can iterate right to left

var myNodeList = document.getElementsByTagName('HR');
for (var i = myNodeList.length; --i >= 0;) {
  ...
}

so that when you remove an item, there is nothing to the right that shifts left messing up your indexing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM