2011-01-18 16 views
22

Tengo una tabla como la siguiente:No se puede establecer innerHTML en tbody en IE

<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> 

y un método que me devuelve lo siguiente después de una petición AJAX:

<tr> 
    <td>data 1 new</td> 
    <td>data 2 new</td> 
    <td>data 3 new</td> 
    <td>data 4 new</td> 
</tr> 

quiero cambiar el innerHtml como

document.getElementById('replaceMe').innerHTML = data.responseText; 

sin embargo, parece que el IE no puede establecer innerHTML en <tbody>. ¿Alguien puede ayudarme con una solución simple para este problema?

+2

también, utilizando una biblioteca como jQuery NO es una opción. – tester

Respuesta

32

Eso es cierto, innerHTML en elementos tbody es de sólo lectura en el IE

La propiedad es de lectura/escritura para todos los objetos excepto los siguientes, para la que es de sólo lectura: COL, COLGROUP, FRAMESET, HEAD, HTML, STYLE, TABLE, TBODY, TFOOT, THEAD, TITLE, TR.

fuente: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx

Usted puede hacer algo como esto para trabajar alrededor de ella:

function setTBodyInnerHTML(tbody, html) { 
    var temp = tbody.ownerDocument.createElement('div'); 
    temp.innerHTML = '<table>' + html + '</table>'; 

    tbody.parentNode.replaceChild(temp.firstChild.firstChild, tbody); 
} 

Básicamente se crea un nodo temporal en el que se inyecta una completa table. Luego reemplaza el tbody con el tbody del table inyectado. Si resulta ser lento, puede hacerlo más rápido almacenando en caché temp en lugar de crearlo cada vez.

+0

¿cómo puedo usar esto? –

+1

var myTableBody = document.getElementById ('valor de tu tbody Id'); setTBodyInnerHTML (myTableBody, "valor para agregar"); – Matoeil

+2

No tan bueno: el reemplazo pierde todos los atributos originales, como id = "replaceMe" en la pregunta. –

6

crear un nodo temporal para almacenar una tabla en, a continuación, copiarlos a la 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); 
    } 
1

Tanto las respuestas anteriores parecer un poco confuso. Además, el div creado nunca se elimina, por lo que llamar a esas funciones repetidamente come memoria. Prueba esto:


// 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;  

Incluso con este código, sin embargo, MSIE no parece cambiar el tamaño adecuadamente las celdas de la tabla en mi solicitud, pero estoy llenando una etiqueta tbody vacío con contenido variable generada, mientras que la culata en T los valores de colspan de las celdas se establecen en un valor fijo: la cantidad máxima de celdas que puede haber en el tbody generado. Mientras que el cuerpo de la mesa tiene 50 celdas de ancho, solo se muestran dos columnas. Quizás si la tabla se llenara originalmente y las celdas se reemplazaran con la misma estructura interna, este método funcionaría. Chrome de Google hace un excelente trabajo de reconstrucción de la tabla, mientras que el navegador de escritorio de Opera puede cambiar el tamaño de más columnas, pero si quitas columnas, el ancho restante de las columnas sigue siendo tan estrecho como antes; sin embargo, con Opera, ocultando la tabla (display = none) y volviéndola a mostrar (display = table), las celdas tbody de la tabla generada se dimensionan correctamente. Me he dado por vencido con Firefox. Es el MSIE-6 de 2012: una pesadilla para desarrollar para la cual se debe agregar un marcado adicional solo para hacer que los diseños de HTML-CSS funcionen porque no se ajusta a los estándares que incluso ahora MSIE hace. Así que no he probado el funcionamiento de tbody.innerHTML en Firefox.

+2

El nodo obtiene la recolección de basura después de que la función finaliza, ya que no está adjunta al DOM. –

1

Esto puede solucionarse creando un shim/polyfill para .innerHTML.Esto podría conseguir que (usted, querido lector) comenzar:

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) 

http://jsfiddle.net/DLLbc/9/

0

me encontré en la misma situación hoy.

Resolví mi problema reemplazando el marcado completo de la tabla con divs flotantes y css que simulan el comportamiento de la tabla. De esta forma, pude usar innerHTML en IE sin problemas.

Si bien esto no podría ser una solución para nadie, si se le permite su tabla con divs flotantes le sugiero que lo haga.

0
<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> 
+0

¿Podría agregar un breve resumen de la solución propuesta? – mrtig

Cuestiones relacionadas