Why does jQuery's $().each() function seem to be losing track of the DOM?
- by Nate Wagar
I've recently started encountering a very strange problem. To be honest, I'm not entirely sure how to describe it other than to just show it.
Here's the relevant HTML:
<div class="component container w100 noEdit" id="contentWrapper">
<div class="component container w50" id="container1">
<div class="component text w50" id="text1">
Text1
</div>
</div>
<div class="component container w25" id="container2">
Container2
</div>
<div class="component container w25" id="container3">
Container3
</div>
<div class="component container w25" id="container4">
Container4
</div>
</div>
And the relevant JavaScript:
$(document).ready(function () {
//Add the Grab Bar to container components on the page.
$('.component').each(wrapComponentForEdit);
$('#contentWrapper').sortable();
$('#contentWrapper').disableSelection();
});
var wrapComponentForEdit = function()
{
if (!$(this).hasClass('noEdit')) {
$(this).html('<div class="componentBorder">' + $(this).html() + '</div>');
$(this).prepend('<div class="grabBar_l"><div class="grabBar_r"><div class="grabBar"></div></div></div>');
alert($(this).attr('id'));
}
}
The end result of this is that I see an alert pop up for container1, text1, container2, container3, container 4. And yet only the containers (not the text) end up with the visual changes that the $().each() is supposed to make.
Anyone have any idea what the heck is going on?
Thanks!
EDIT - A different way to do it, that still fails
I tried this, with the same result:
$(document).ready(function () {
//Add the Grab Bar to container components on the page.
var matched = $('.component');
var componentCount = $(matched).size();
for (i = 0; i < componentCount; i++)
{
wrapComponentForEdit($(matched).eq(i));
}
$('#contentWrapper').sortable({ handle: '.grabBarBit', tolerance: 'pointer'});
$('#contentWrapper').disableSelection();
});
var wrapComponentForEdit = function(component)
{
if (!$(component).hasClass('noEdit')) {
$(component).html('<div class="grabBar_l grabBarBit"><div class="grabBar_r grabBarBit"><div class="grabBar grabBarBit"></div></div></div><div class="componentBorder">' + $(component).html() + '</div>');
alert($(component).attr('id'));
}
}
EDIT 2: Another alternate method, but this one works
I tried another way of doing things, and this way it works. However, the initial question still stands. Judging by how this new way works, it seems to me that the DOM is being updated, but jQuery isn't updating with it, so it loses track of the child element.
$(document).ready(function () {
//Add the Grab Bar to container components on the page.
var componentCount = $('.component').size();
for (i = 0; i < componentCount; i++)
{
wrapComponentForEdit($('.component').eq(i));
}
$('#contentWrapper').sortable({ handle: '.grabBarBit', tolerance: 'pointer'});
$('#contentWrapper').disableSelection();
});
var wrapComponentForEdit = function(component)
{
if (!$(component).hasClass('noEdit')) {
$(component).html('<div class="grabBar_l grabBarBit"><div class="grabBar_r grabBarBit"><div class="grabBar grabBarBit"></div></div></div><div class="componentBorder">' + $(component).html() + '</div>');
alert($(component).attr('id'));
}
}