Подтвердить что ты не робот

Невозможно установить innerHTML на tbody в 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>

и после запроса ajax метод возвращает мне следующее:

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

Я хочу изменить innerHTML как

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

Однако, похоже, что IE не может установить innerHTML на <tbody>. Может ли кто-нибудь помочь мне с простым обходным решением для этой проблемы?

4b9b3361

Ответ 1

Это верно, innerHTML на элементах tbody читается только в IE

Свойство читается/записывается для всех объектов, за исключением следующих, для который доступен только для чтения: COL, COLGROUP, FRAMESET, HEAD, HTML, STYLE, TABLE, TBODY, TFOOT, THEAD, TITLE, TR.

источник: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx

Вы можете сделать что-то вроде этого, чтобы обойти это:

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

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

В основном создается временный node, в который вы вводите полный table. Затем он заменяет tbody на tbody из введенного table. Если он окажется медленным, вы можете сделать это быстрее, кэшируя temp, а не создавая его каждый раз.

Ответ 2

Создайте temp node, чтобы сохранить таблицу, а затем скопируйте их в 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);
  } 

Ответ 3

Оба приведенных выше ответа кажутся немного неясными. Кроме того, созданный div никогда не удаляется, поэтому вызов этих функций многократно ест память. Попробуйте следующее:


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

Однако даже с этим кодом MSIE, похоже, не правильно меняет размеры ячеек таблицы в моем приложении, но я заполняю пустой тег тэга переменным сгенерированным контентом, в то время как значения colspan ячеек thead устанавливаются в фиксированное значение: максимальное количество ячеек, которые могут быть в сгенерированном теле. Пока таблица tbody имеет ширину 50 ячеек, отображаются только две колонки. Возможно, если таблица была первоначально заполнена, и ячейки были заменены одной и той же внутренней структурой, этот метод будет работать. Google Chrome отлично справляется с перестройкой таблицы, в то время как браузер Opera для рабочего стола может изменять размер до большего количества столбцов, но если вы удаляете столбцы, оставшиеся ширины столбцов остаются такими же узкими, как и они; однако с Opera, скрывая таблицу (display = none), затем повторно отображая ее (display = table), сгенерированные ячейки tbody таблицы затем правильно определяют. Я отказался от Firefox. Это MSIE-6 2012 года - кошмар для разработки, для которого должна быть добавлена ​​дополнительная разметка, чтобы сделать макеты HTML-CSS, потому что он не соответствует стандартам, которые даже MSIE делает сейчас. Поэтому я не тестировал работу tbody.innerHTML в Firefox.

Ответ 4

Это можно устранить, создав шайбу / polyfill для .innerHTML. Это может вас заставить (вы, дорогой читатель) начать:

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/

Ответ 5

Сегодня я оказался в такой же ситуации.

Я решил свою проблему, заменив всю табличную разметку плавающими divs и css, которые имитируют поведение таблицы. Таким образом, я смог без проблем использовать innerHTML в IE.

Хотя это не может быть решением для всех, если вам разрешено использовать таблицу с плавающими div, я предлагаю вам сделать это.

Ответ 6

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