nemobluesix Posted May 7, 2010 Share Posted May 7, 2010 Hello,As you all know, IE is buggy when working with attribute innerHTML of tables. So, when getting data with ajax, instead of setting this attribute to the responseText, I'm trying to create a fragment then append it to the table as child node. In case you are wondering why I don't read the whole table, I need to set both thead and tbody from two separate ajax requests.The problem is that the fragment, even if it is correct, does not show as expected. I made a test page to reproduce the problem. Do not use Internet Explorer to test this . <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>test</title> <script type="text/javascript">function testf(opt){ str="<tr id=\"one\"><td>row no. 1</td></tr><tr id=\"two\"><td>row no. 2</td></tr><tr id=\"three\"><td><input type=\"text\"/></td></tr>"; var tb=document.getElementById("thebody"); if(opt) appendCells(tb,str); else tb.innerHTML=str;}function appendCells(tb,resp){ var firstNodeElem=0; xmlDoc=loadXMLString("<root>"+resp+"</root>");//like in the example, I sometimes get nodes without a root element fragment = document.createDocumentFragment(); nodes=xmlDoc.firstChild.childNodes;//get the row nodes for(i=0;i<nodes.length;i++){ if(!firstNodeElem && nodes[i].nodeType==1) firstNodeElem=i;//save the index of the first element node fragment.appendChild(nodes[i].cloneNode(true));//add to the fragment } while(tb.hasChildNodes()) tb.removeChild(tb.firstChild);//empty the body, new nodes are comming var str= (new XMLSerializer()).serializeToString(fragment); tb.appendChild(fragment); //show the content in textareas document.getElementById("frag").value=str; document.getElementById("innerH").value=tb.innerHTML;}function loadXMLString(txt) { if (window.DOMParser) { parser=new DOMParser(); xmlDoc=parser.parseFromString(txt,"text/xml"); } else // Internet Explorer { xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async="false"; xmlDoc.loadXML(txt); } return xmlDoc;} </script> <style type="text/css"> table tr td{ border: 1px solid red; } textarea{ width:300px; height:300px; } </style></head><body> <input type="button" value="modify by innerHTML" onclick="testf(0)"/> <input type="button" value="modify by fragment" onclick="testf(1)"/> <table id="thetable"> <tbody id="thebody"> <tr><td>press the buttons to modify the table</td></tr> </tbody> </table> <table><tr><td>fragment content<br/><textarea id="frag"></textarea></td><td>innerHTML content<br/><textarea id="innerH"></textarea></td></tr></table></body></html> I don't even know where to stat digging Link to comment Share on other sites More sharing options...
jeffman Posted May 7, 2010 Share Posted May 7, 2010 That's a pretty unconventional approach. You're correct, innerHTML is bad news for populating tables. But document fragments are a totally unnecessary middle step. The normal functions are tableObj.insertRow() and rowObj.insertCell.There is a pretty good example here. Obviously you'd need to make changes. A big change is what you've already figured out: add elements to a <tbody> element, not a <table> element itself. Fortunately, functions that work for a table also work for a tbody. Link to comment Share on other sites More sharing options...
nemobluesix Posted May 7, 2010 Author Share Posted May 7, 2010 thanks Deirdre's Dad for your reply.I choose the fragment way because in my real program I get more than simple tables. My cells can also contain form elements, anchors etc. So the insertRow and insertCell functions are insufficient and I think it's very complicated to check the tagName of every element.So far, after googling around I learned that inserting xml in the html dom will not work and I wrote a personal version of cloneNode. It might not work for everything, I didn't even test it very carefully but I'm posting it here to get some feed back :)In the test page posted earlier replace the line that reads: fragment.appendChild(nodes[i].cloneNode(true));//add to the fragment with var newn=myClone(nodes[i]);if(newn) fragment.appendChild(newn); and add a new function: function myClone(node){ if(!node) return null; var newn; switch(node.nodeType){ case 1:// ELEMENT_NODE newn=document.createElement(node.nodeName); break; case 3:// TEXT_NODE newn=document.createTextNode(node.nodeValue); break; case 4:// CDATA_SECTION_NODE newn=document.createCDATASection(node.nodeValue); break; case 2:// ATTRIBUTE_NODE case 5:// ENTITY_REFERENCE_NODE case 6:// ENTITY_NODE case 7:// PROCESSING_INSTRUCTION_NODE case 8:// COMMENT_NODE case 9:// DOCUMENT_NODE case 10:// DOCUMENT_TYPE_NODE case 11:// DOCUMENT_FRAGMENT_NODE case 12:// NOTATION_NODE alert("untreated "+node.nodeType); break; } var atts=node.attributes; for(var i=0;atts && i<atts.length;i++){ newn.setAttribute(atts[i].nodeName,atts[i].nodeValue); } var c=node.firstChild; while(c){ var newc=myClone(c); if(newc){ newn.appendChild(newc); } c=c.nextSibling; } return newn;} For some reason, attributes are not listed in the childNode collection so I treated them in a separate loop; maybe somebody can clear why this happens.And another issue is that the <input> element is not closed correctly (like <input/>). I'm still digging for this... Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.