Panasonic Youth rob sanheim writes about software, business, ruby, music, stuff and things



Posted
11 October 2005 @ 3pm

Tagged
Ajax, Open Source, Rails

Discuss

Prototype Insertion, IE 6, tr’s, and “invalid target element for this operation…”

After much hardship I’m giving up on trying to use Prototype’s Insertion function for inserting new rows after a specified target row. Everything I try works in Firefox but blows out in IE 6, which is the “supported platform”. After some searching it seems IE has inconsistent support for the insertAdjacentHTML method, and apparently for elements like TR and TBODY IE will throw an exception if the method is called on those methods. In the latest prerelease there is a fix for tbodys, but nothing for tr, and my knowledge of dom manipulation fell short when trying to hack that in. If anyone can see how to add that to prototype.js, please let me know. This seems like something that would be commonly done with Rails apps for dynamically adding rows to a table, so its curious that I couldn’t find anything via Google…


32 Comments

Posted by
Jeff
17 October 2005 @ 3pm

Good lord yes! Why does no one have a working solution to this? I too have searched google and could not get a good answer.

On this page: http://neo.dzygn.com/archive/2004/02/the-ie-factor Mark wrote his own implementation of importNode to try and resolve this sort of problem, but I have not been able to get it to work for some reason…

If you have since found a solution or anyone else knows please help.


Posted by
Rahul Gupta
24 October 2005 @ 1pm

Hi all, I’m not sure if this will be helpful, but I’ll give it a shot. I haven’t dug into prototype.js yet–we’ve been developing our own stuff in-house.

I’m building an invoicing component where a user might want to insert a new line item between 2 existing line items. I ended up using the insertBefore() method.

invoice.insertRowBefore = function(currentRowID){

var tableNode = document.getElementById(”invoiceLineItems”).tBodies[0];
var currentRow = document.getElementById(currentRowID);
var newRow = document.createElement(”tr”);
tableNode.insertBefore(newRow,currentRow);

}

But if you want to add something to the end of the table, you can just appendChild() to the ‘tableNode’ as referenced above. I guess you could create function to check if you’re adding the row to the end or not and then call the correct whichever function was appropriate.

Does that help or did I completely misunderstand what you’re trying to do here?


Posted by
Rahul Gupta
24 October 2005 @ 1pm

Heh. Unless you wanted to do this with innerHTML… then, well… then, I’m a fool.

I think I’m a fool.


Posted by
Noel Grandin
25 October 2005 @ 5am

Wrap the text in table tags and create an invisible element somewhere using insertAdjacentHtml().
Then use cloneNode() and insertBefore() to copy the row DOM node.
Hackish, but it might work.


Posted by
Rob
25 October 2005 @ 6pm

Thanks for all the suggestions. What I ended up doing was using multiple tbody’s inside of one table, as DWR has a addRows function that worked nicely for appending rows to the end of any “table object” (tbody, table, etc). After all that, though, it looks like we might end up doing something else using nested tables, as the elements to insert should probably be a their own table if its to be correct semantically.


Posted by
Mike Blake
22 November 2005 @ 12am

Had to let you know my hack because it is strange but simple.

For some reason Insertion.Before does the job!

But to make it work, in your HTML snippet that gets sent via AJAX, you need anto ad a after you’ve closed the TR tag. Without this the value get appended vertically.

This got the desired effect in both browsers.


Posted by
Mike Blake
22 November 2005 @ 12am

Again without the < and > ..

Insert.Before

… to make it work, in your HTML snippet that gets sent via AJAX, you need to add a BR after you’ve closed the TR tag. Without this the value get appended vertically.


Posted by
Rob
22 November 2005 @ 5pm

Thanks for the tip, Mike. I’ll have to give that try.


Posted by
Andy
12 December 2005 @ 1pm

This fix works for me in the 1.4.0_rc4 release. In the Abstract.Insertion.prototype, add a check for TR:

if (this.element.tagName.toLowerCase() == ‘tbody’
|| this.element.tagName.toLowerCase() == ‘tr’) {
this.insertContent(this.contentFromAnonymousTable());

I didn’t need the extra BR tag.


Posted by
ceejayoz
5 January 2006 @ 12am

Andy’s fix works like a charm.

It’s on line 1036 of the 1.4.0 release.


Posted by
Andrew
16 January 2006 @ 10pm

Or, you could re-render the whole table including the new row, and replace it entirely during the ajax call.

Start with Table v.1
User adds row of information
System generates Table v.2
System swaps the entire v.1 with the entire v.2.


Posted by
Larry
2 February 2006 @ 3pm

I have been playing around with a replacement for the innerHTML implementation in Prototype. If you are interested, you can check it out here:

http://www.larrygoats.com/articles/2006/01/26/taconite-prototype-rails


Posted by
Mandy
21 February 2006 @ 6am

I tried using Andy’s fix, but it did not work for me. I am on prototype 1.5.0_pre0. Does anyone know how to address it?

Thanks in advance,
Mandy.


Posted by
Blaise
19 March 2006 @ 5pm

Is it possible that it don’t work too while adding s to a ??


Posted by
Vidar S. Ramdal
29 March 2006 @ 8am

I also used Andy’s genious fix. However, for me, the rows where added in the reverse order.

So, I modified the line

this.insertContent(this.contentFromAnonymousTable())

to

this.insertContent(this.contentFromAnonymousTable()._reverse());


Posted by
Venelin Mihaylov
10 April 2006 @ 3am

For me Andy’s fix also works. Thanks dude! :)


Posted by
Sunita
10 April 2006 @ 3pm

Thanks, Andy.. The fix works great :)


Posted by
Chris Nolan.ca
15 April 2006 @ 2am

Looks like it’s been patched.

http://dev.rubyonrails.org/changeset/4150

Also a ticket @ http://dev.rubyonrails.org/ticket/4633 dealing with the reverse issue.

However something still seems to be fishy with it because it’s still busted for me. Still investigating but thought I’d put the links up here.


Posted by
Chris Nolan.ca
15 April 2006 @ 3am

My problem was I was trying to insert a tr into a table instead of into a tbody. Whoops.

Details are @ http://kekova.ca/articles/2006/04/15/ie_prototype_tr_error


Posted by
Jimi
16 April 2006 @ 5pm

Andy’s fix worked! :D


Posted by
Zlatan
17 May 2006 @ 5pm

I had the same problem as Chris, even with the fix it din’t work, this was because I wasn’t using a tag I was inserting rows directly within tags.

According to http://www.w3.org/TR/html4/struct/tables.html and http://www.htmlhelp.com/reference/html40/tables/tbody.html a tbody is optional


Posted by
John Wolfe
14 June 2006 @ 7pm

Help Chris!

I have been trying to follow the new O’Reilly book “RJS Templates for Rails” - and ran into this problem with IE 6.

I spent a few hours trying to recreate the fix that Chris Nolan described, but I am just not familiar enough with javascript / dom / prototype.js.

Chris, could you publish either a diff or a listing around the critical Abstract.Insertion.prototype function? Or could someone else who has peiced together the magic help out?

Thanks!! You guys are great!


[...] This bug bit me and fixing it was a pain. I finally found a fix in Andy’s comment at Rob Sanheim’s Panasonic Youth Weblog. The fix? Modify line 1032 in prototype-1.4.0.js to: if (this.element.tagName.toLowerCase() == ‘tbody’ || this.element.tagName.toLowerCase() == ‘tr’) { this.insertContent(this.contentFromAnonymousTable()); } [...]


Posted by
CeyloR
17 August 2006 @ 3pm

Thanks Andy,

this fix works great!!!


Posted by
two solutions - part 1
1 December 2006 @ 7pm

td.innerHTML = sometext; works in IE (tested in IE6). So only tr needs to be copied using dom methods. Problem with all dom variants discussed earlier is with copying attributes and handlers. I ended up with the shaky hack for attributes. Do not know a general solution for event handlers. ‘true’ and ‘false’ are returned as strings. ‘disabled’ attribute gave me trouble too. Who know what else is in stock. So - take a look at ‘two solutions - part 2′ which worked much better for me.

function copyAttributes(oNode, oNew) {
for(var i = 0; i


Posted by
two solutions - part 1
1 December 2006 @ 7pm

function copyAttributes(oNode, oNew) {
for(var i = 0; i


Posted by
Henry Goff. Two solutions - part 2
1 December 2006 @ 7pm

all problems went away when i switched from iframe-based ajax to xmlHttpRequest. I did:
var d1 = document.createElement(’div’); d1.innerHTML = content; // content returned by xmlHttpRequest. After that i used both insertBefore appendChild to copy TR from the table in div d1 into another table on the page.


Posted by
Dat
12 January 2007 @ 4am

when i use Abstract.InsertionParent.Bottom, the problem occurs again.


Posted by
Dat
14 January 2007 @ 9pm

When I insert following code in insertContent function of InsertionParent.Bottom, i’m successful

var tempDiv = opener.document.createElement(”div”);
tempDiv.innerHTML = ” + fragment.outerHTML + ”; this.element.appendChild(tempDiv.getElementsByTagName(’tr’).item(0));


Posted by
Dat
14 January 2007 @ 9pm

When I insert following code in insertContent function of InsertionParent.Bottom, i’m successful

var tempDiv = opener.document.createElement(�div�);
tempDiv.innerHTML = “ + fragment.outerHTML + “; this.element.appendChild(tempDiv.getElementsByTagName(’tr’).item(0));


Posted by
Peter
3 June 2007 @ 3pm

Not sure if anybody will read this as it is so long since the last post, but as this was the first item I found in Google on this subject, and I have been having trouble with the same issue, here’s what I have discovered…
Using new Insertion.Before() on a element with an ID does not work (for me) on IE. However, place a … element into the table and *transfer the ID from the table element to the tbody element*, and it works.
In other words, perform the Insertion on a element, not a element. Simple as that. Works a treat. Why this should be necessary, I just don’t know.


Posted by
JN2
2 October 2007 @ 6am

Bottom line for me: use ‘tbody’ and ‘thead’ so IE6 works. Don’t insert ‘tr’s directly into ‘table’.


Leave a Comment

JIA - Matt Raible - Comparing Java Web Frameworks Ajax ToDo list application #437