12

Is there a way to copy an element without copying it's children?

My goal is to duplicate a table, along with all classes, inline styles, etc. But I do not want to copy any of the table element's children.

I realize I could copy the entire table and then remove the children from the copy. But I want to minimize screen flicker and I seem to recall there are problems manipulating elements before they are visible in the DOM.

Any suggestions?

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • 2
    Cloning the entire table, emptying it and *then* adding it to the DOM should not cause any flicker. Can you reproduce the flicker issue? – techfoobar Mar 18 '14 at 03:13
  • you can clone the element, remove its children then add it to the dom... but if you clone, add to dom then remove the children might cause some problem(atleast might result in performance wise) – Arun P Johny Mar 18 '14 at 03:13
  • @techfoobar: It can be a very large table. It would at least cause a delay I'm sure. I'm willing to experiment with the flicker, but recall running into problems trying to manipulate elements that were not yet visible. Would you make the cloned table visible while deleting the unneeded children? – Jonathan Wood Mar 18 '14 at 03:16
  • @JonathanWood: You can manipulate a "disconnected" node the same as if it was part of the document. There is only a difference if you are trying to get information that makes only sense when the element is part of the document, like it's position in screen coordinates. Most DOM manipulation methods work the same regardless. – Felix Kling Mar 18 '14 at 03:20

3 Answers3

15

Have you considered using native cloneNode? The argument controls whether children should be cloned as well.

var clone = table.cloneNode(false);

This does not clone event handlers though. I'm not sure about styles set via the DOM API (probably not).

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • if you mean `element.style.fontSize=...` it will get added to the style attribute so it gets cloned – Patrick Evans Mar 18 '14 at 03:21
  • [Indeed it does](http://jsfiddle.net/26kkh/). I wasn't sure because the MDN documentation mentions that event handlers are not cloned either. – Felix Kling Mar 18 '14 at 03:23
  • Thank you. Never knew about `cloneNode()` – techfoobar Mar 18 '14 at 03:37
  • 1
    Regarding listeners, those added inline (i.e. as HTML attributes) are cloned, as are those added using IE's *attachEvent*. But those added using *addEventListener* or directly as a property are not (per the W3C [*Interface EventListener*](http://www.w3.org/TR/DOM-Level-3-Events/#interface-EventListener)) – RobG Mar 18 '14 at 05:34
1

use .cloneNode

var t = document.createElement("table");
t.setAttribute("style",'background:#0F0; font-size:12px;');
var tr = document.createElement("tr");
var td = document.createElement("td");
td.appendChild(document.createElement("input"));
tr.appendChild(td);
t.appendChild(tr);
var clone = t.cloneNode();
console.log(clone);
//outputs 
//<table style="background:#0F0; font-size:12px;"></table>
Patrick Evans
  • 41,991
  • 6
  • 74
  • 87
  • Note that in older versions of IE, TR elements must be appended to a TBODY element, not to a TABLE element. An alternative is to create the TR using [*table.insertRow*](http://www.w3.org/TR/html5/tabular-data.html#dom-table-insertrow), which appends a row to the table's TBODY, or creates one if there isn't one already available. – RobG Mar 18 '14 at 05:41
0

This is just another way to do it, probably the ugliest one so far posted, but I'm just adding to the possibilities. If it were me, I would use the one by Felix Kling.

It basically gets the outerHTML and innerHTML substracting one to the other: table.prop('outerHTML').replace(table.prop('innerHTML'), '');. Here's a demo.

HTML

<table class="some-class" style="border:1px solid #000" id="t">
    <tr>
        <td>first</td>
    </tr>
</table>

JS

$(function () {
    $('#t').addClass('another-class');
    var table = $('#t')
    var html = table.prop('outerHTML').replace(table.prop('innerHTML'), '');
    $('body').append($(html).append('<tr><td>second</td></tr>'));
});

CSS

.some-class {
    color: #00F
}
.another-class {
    color: #00F;
    font-size: 18px;
}
Community
  • 1
  • 1
juan.facorro
  • 9,791
  • 2
  • 33
  • 41