Unable to set innerHTML to tbody in IE
I have a table like this:
<table> <thead> <tr> <th colspan="1">a</th> <th colspan="3">b</th> </tr> </thead> <tbody id="replaceMe"> <tr> <td>data 1</td> <td>data 2</td> <td>data 3</td> <td>data 4</td> </tr> </tbody> </table> and after an ajax request, the method returns me the following:
<tr> <td>data 1 new</td> <td>data 2 new</td> <td>data 3 new</td> <td>data 4 new</td> </tr> I want to change innerHTML as
document.getElementById('replaceMe').innerHTML = data.responseText; However, it seems that IE cannot set innerHTML to <tbody> . Can someone help me with a simple workaround for this problem?
That's right, innerHTML on tbody elements is read only in IE
The property is read / written for all objects except the following, for which it is read-only: COL, COLGROUP, FRAMESET, HEAD, HTML, STYLE, TABLE, TBODY, TFOOT, THEAD, TITLE, TR.
source: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
You can do something like this to get around this:
function setTBodyInnerHTML(tbody, html) { var temp = tbody.ownerDocument.createElement('div'); temp.innerHTML = '<table>' + html + '</table>'; tbody.parentNode.replaceChild(temp.firstChild.firstChild, tbody); } Basically a temporary node is created into which you enter the full table . Then it replaces tbody with tbody from the entered table . If it turns out to be slow, you can do it faster by caching temp rather than creating it every time.
Create a temp node to save the table and then copy them to tbody
var tempNode = document.createElement('div'); tempNode.innerHTML = "<table>" + responseText+ "</table>"; var tempTable = tempNode.firstChild; var tbody = // get a reference to the tbody for (var i=0, tr; tr = tempTable.rows[i]; i++) { tbody.appendChild(tr); } Both of the above answers seem a bit unclear. In addition, the created div is never deleted, so calling these functions eats memory many times. Try the following:
// this function must come before calling it to properly set "temp" function MSIEsetTBodyInnerHTML(tbody, html) { //fix MS Internet Exploder's lameness var temp = MSIEsetTBodyInnerHTML.temp; temp.innerHTML = '<table><tbody>' + html + '</tbody></table>'; tbody.parentNode.replaceChild(temp.firstChild.firstChild, tbody); } MSIEsetTBodyInnerHTML.temp = document.createElement('div'); if (navigator && navigator.userAgent.match( /MSIE/i )) MSIEsetTBodyInnerHTML(tbody, html); else //by specs, you can not use "innerHTML" until after the page is fully loaded tbody.innerHTML=html; However, even with this code, MSIE does not seem to correctly resize table cells in my application, but I fill the empty tag tag with variable generated content, while the colspan values ββof thead cells are set to a fixed value: the maximum number of cells that can be in generated body. As long as the tbody table is 50 cells wide, only two columns are displayed. Perhaps if the table was originally populated and the cells were replaced with the same internal structure, this method will work. Google Chrome does a great job of rebuilding the table, while Opera's desktop browser can resize to more columns, but if you delete columns, the remaining column widths remain as narrow as they are; however, with Opera, hiding the table (display = none), then re-displaying it (display = table), the generated tbody cells of the table are then correctly detected. I abandoned Firefox. This 2012 MSIE-6 is a development nightmare for which additional markup must be added in order to make HTML-CSS layouts because it does not meet the standards that even MSIE does now. Therefore, I have not tested the operation of tbody.innerHTML in Firefox.
This can be fixed by creating a / polyfill washer for .innerHTML. This can make you (you, dear reader) start:
if (/(msie|trident)/i.test(navigator.userAgent)) { var innerhtml_get = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "innerHTML").get var innerhtml_set = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "innerHTML").set Object.defineProperty(HTMLElement.prototype, "innerHTML", { get: function () {return innerhtml_get.call (this)}, set: function(new_html) { var childNodes = this.childNodes for (var curlen = childNodes.length, i = curlen; i > 0; i--) { this.removeChild (childNodes[0]) } innerhtml_set.call (this, new_html) } }) } var mydiv = document.createElement ('div') mydiv.innerHTML = "test" document.body.appendChild (mydiv) document.body.innerHTML = "" console.log (mydiv.innerHTML) Today I found myself in the same situation.
I solved my problem by replacing all the table layout with floating divs and css that mimic the behavior of the table. Thus, I was able to use innerHTML in IE without any problems.
Although this may not be the solution for everyone, if you are allowed to use a table with floating divs, I suggest you do it.
<table id="table"> <thead> <tr> <th colspan="1">a</th> <th colspan="3">b</th> </tr> </thead> <tbody id="replaceMe"> <tr> <td>data 1</td> <td>data 2</td> <td>data 3</td> <td>data 4</td> </tr> </tbody> </table> <button type="button" onclick="replaceTbody()">replaceTbody</button> <script> function $(id){ return document.getElementById(id); } function replaceTbody(){ var table = $('table'); table.removeChild($('replaceMe')); var tbody = document.createElement("tbody"); tbody.setAttribute("id","replaceMe"); table.appendChild(tbody); var tr = document.createElement('tr'); for(var i=1;i<5;i++){ var td = document.createElement('td'); td.innerHTML = 'newData' + i; tr.appendChild(td); } tbody.appendChild(tr); } </script>