PDA

View Full Version : Bug in DomHelper/Template - inserting table rows



jarrednicholls
7 Jan 2007, 7:52 PM
Hey Jack,

My buddy Aaron and I found a bug tonight when trying to do an insertBefore on a template of a table row into a table. Here was the problem code:


if (table.tBodies[0].rows[0]) {
tpl.insertBefore(table.tBodies[0].rows[0], {profilename: 'My Profile', id: id});
} else {
tpl.append(table.tBodies[0], {profilename: 'My Profile', id: id});
}

The template is of a tr element. So intuitively, one would think "if I want to insert my tr template before another tr, I would pass in that specific tr as the element to the insertBefore function". This yields a wicked bug in the insertHtml function of the DomHelper class:


var insertIntoTable = function(tag, where, el, html){

if(!tempTableEl){

tempTableEl = document.createElement('div');

}

var node;

if(tag == 'table' || tag == 'tbody'){

tempTableEl.innerHTML = '<table><tbody>'+html+'</tbody></table>';

node = tempTableEl.firstChild.firstChild.firstChild;

}else{

tempTableEl.innerHTML = '<table><tbody><tr>'+html+'</tr></tbody></table>';

node = tempTableEl.firstChild.firstChild.firstChild.firstChild;

}

if(where == 'beforebegin'){

el.parentNode.insertBefore(node, el);

return node;

}else if(where == 'afterbegin'){

el.insertBefore(node, el.firstChild);

return node;

}else if(where == 'beforeend'){

el.appendChild(node);

return node;

}else if(where == 'afterend'){

el.parentNode.insertBefore(node, el.nextSibling);

return node;

}

}

As you know, the insertIntoTable function is called by the insertHtml function because the passed element has the tr tagName. In the code above, you see that if the tagName is NOT table or tbody, then this code runs:


else{

tempTableEl.innerHTML = '<table><tbody><tr>'+html+'</tr></tbody></table>';

node = tempTableEl.firstChild.firstChild.firstChild.firstChild;

}

This is problematic because our template is a tr element. And a tr element being put into a tr element doesn't work! :-) So the natural thing to do is pass in the tbody element, riiight?


if (table.tBodies[0].rows[0]) {
tpl.insertBefore(table.tBodies[0], {profilename: 'My Profile', id: id});
} else {
tpl.append(table.tBodies[0], {profilename: 'My Profile', id: id});
}

Ok, so this makes it so our tr template gets put into a tbody in your tempTableEl code in the insertIntoTable function. Good. But this still isn't good, because the insertBefore function uses the 'beforebegin' where clause, which runs this code:


if(where == 'beforebegin'){

el.parentNode.insertBefore(node, el);

return node;

}

Not good. Our tr is being put into the table before the tbody element. Well ! We're close though. Here was the final fix, going straight through to the DomHelper since there was no wrapper for the 'afterbegin' where clause:


if (table.tBodies[0].rows[0]) {
YAHOO.ext.DomHelper.insertHtml('afterbegin', table.tBodies[0], tpl.applyTemplate({profilename: 'My Profile', id: id}));
} else {
tpl.append(table.tBodies[0], {profilename: 'My Profile', id: id});
}

Great, that works, because the afterbegin runs this code:


else if(where == 'afterbegin'){

el.insertBefore(node, el.firstChild);

return node;

}

Perfect! So you see, having a tr template and trying to do an insertBefore another row intuitively would seem to work just fine, but it does not. Can you put this on your low priority to-do list?

Thanks for all the hard work Jack!

EDIT: This isn't so reliable in IE either. But perhaps you can test a bit and find a good solution to such a problem. We all appreciate it!

jack.slocum
8 Jan 2007, 10:21 AM
Inserting into tables and selects is always a nightmare in IE. I will go through that code very soon and give it an upgrade. Sorry about the lost time.