4

I have been trying to clone polymer elements - typically elements that have been created from data of some kind, so it is not an option to just create a new instance of the template with the constructor or document.createElement.

  • element.cloneNode does not work on its own as it does not copy the shadow-root
  • lodash proposed by Polymer Clone Objects does not seem to do anything (cloned object is empty)
  • cloneEl.shadowRoot.innerHTML = sourceEl.shadowRoot.innerHTML; copies the shadow-root, but seems to lose the binding

Extensive example: http://jsbin.com/vitumuwayu/3/edit

Is there a Polymer.cloneNode function I have been unable to find?

Community
  • 1
  • 1
ootwch
  • 930
  • 11
  • 32

2 Answers2

2

I have finally found an answer to this question (at least for Polymer 1.0).

https://stackoverflow.com/a/6620327/1878199 shows how to copy properties. https://stackoverflow.com/a/25187164/1878199 describes how to get the list of properties for a polymer element.

The answer is then:

newElement = element.cloneNode(true);
for(var i in element.properties) {
            newElement[i] = element[i]
          }

Full illustrated and working example on jsbin or in the snippet below.

<!DOCTYPE html>

<html>

<head>

  <link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.0.1/lib/polymer/polymer.html">



  <meta charset="utf-8">
  <title>Polymer Cloning Example</title>
</head>

<dom-module id="custom-element">
  <template>
    <div style="border: solid">
      <input type="text" name="some_string" value="{{boundvalue::input}}">
      <p>{{boundvalue}}</p>
    </div>

  </template>
  <script>
    Polymer({
      is: 'custom-element',
      properties: {
        boundvalue: {
          type: String,
          value: 'Enter some text...',
          notify: true
        }
      }
    });
  </script>
  </dom-module>



  <body>

    <custom-element id="source-element"></custom-element>
    <p>
      <button onclick="cloneElementWithoutProperties()">1 Clone the above element into the list below</button>
      <p></p>
      <button onclick="cloneElementWithProperties()">2 Clone the above element into the list below and also copy properties</button>
      <p></p>


      <h3>Test Description</h3>
      <ol>
        <li>Modify text above</li>
        <li>Click Button 1</li>
        <p></p>
        <p>Observed: An element is added below, but it is reset to the original text ('Enter some text...')</p>
        <li>Click Button 2</li>
        <p></p>
        <p>Observed: An element is added below, and it keeps the modified text</p>
        <p>Also verify that the functionality is still ok: Modify the input in the copy, the text is also updated</p>


      </ol>


      <h3>List of cloned elements:</h3>
      <div id='list-elements'>
      </div>

  </body>

</html>

<script>
  function cloneElementWithProperties() {

    list = document.querySelector("#list-elements");
    sourceEl = document.querySelector("#source-element")
    cloneEl = sourceEl.cloneNode(true);
    for (var i in sourceEl.properties) {
      cloneEl[i] = sourceEl[i];
    }
    list.insertBefore(cloneEl, null);

  }

  function cloneElementWithoutProperties() {

    list = document.querySelector("#list-elements");
    sourceEl = document.querySelector("#source-element")
    cloneEl = sourceEl.cloneNode(true);
    list.insertBefore(cloneEl, null);

  }
</script>
Community
  • 1
  • 1
ootwch
  • 930
  • 11
  • 32
  • I found (at least in 1.5) that `cloneNode(true)` creates double paper-checkboxes. Any thoughts on how I could keep polymer from acting on the checkboxes twice? – dlsso Jun 24 '16 at 23:58
  • I was looking for a solution that also clones light DOM children, and this solution did not work for me. – codeMonkey Oct 02 '16 at 17:45
0

This is my clone function.

var clone = function(orig) {
    var ret = orig.cloneNode();
    var lightDom;
    var childNodes;
    if (orig.is && orig.is.toUpperCase() === orig.tagName) {
        lightDom = Polymer.dom(ret);
        childNodes = Polymer.dom(orig).childNodes;
    } else {
        lightDom = ret;
        childNodes = orig.childNodes;
    }
    for (var i = 0; i < childNodes.length; i++) {
        lightDom.appendChild(clone(childNodes[i]));
    }
    return ret;
};
Wasmoo
  • 1,130
  • 9
  • 14