1

For days I try to feed Polymer with some "dynamic" elements :) Unfortunately without success... My goal is to get an element added during runtime and fill it with content by polymer-data-binding (in a "natural" polymer-way. Without a workaround as suggested in another stackoverflow answer.)

Please take a look at the code in this fiddle (https://jsfiddle.net/mkappeller/ken9Lzc7/) or at the bottom of this question. I really hope anyone out there is able to help me out. It would also help to know if there will be a way to do this some day in the future...?


window.addEventListener("WebComponentsReady", function() {
  var myAppModule = document.getElementById("my-app");
  var myApp = document.getElementsByTagName("my-app")[0];

  myApp.set("global", {
    text: "Init"
  });
});
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
<link rel="import" href="paper-button/paper-button.html">
<link rel="import" href="paper-input/paper-input.html">

<dom-module id="my-app">
  <template>
    <paper-input label="global.text" value="{{global.text}}"></paper-input>
    <paper-button raised id="addHeadline">Add Headline</paper-button>
    <paper-button raised id="changeText">Change Text</paper-button>
    <p>global.text: &lt;{{global.text}}&gt;</p>
  </template>
  <script>
    Polymer({
      is: "my-app",
      properties: {
        global: {}
      },
      ready: function() {
        this.count = 0;

        this.$.addHeadline.addEventListener("click", () => {

          var myApp = Polymer.dom(document.getElementById("my-app"));

          var t = myApp.node.childNodes[1];

          var heading = document.createElement("h1");
          heading.textContent = "{{global.text}}";

          // Append to my-app
          Polymer.dom(this.root).appendChild(heading);
        });
        this.$.changeText.addEventListener("click", () => {
          this.set("global.text", "count-" + this.count++);
        });
      }
    });
  </script>
</dom-module>
<my-app></my-app>
Community
  • 1
  • 1
Matt
  • 11
  • 3
  • Do you want to bind all headers to the same text content or do you want them to have their own content? Either way, you should probably use a [`dom-repeat`](https://www.polymer-project.org/1.0/docs/devguide/templates#dom-repeat) binded to an array property – Alan Dávalos Jun 20 '16 at 16:32
  • Hi Alan. I'd like to bind any element to any property. A dom-repeat wouldn't help me here. Because I must define the template content within the dom-repeat. And I can't modify the template content on the fly. – Matt Jun 20 '16 at 17:50
  • Do you need two-way binding or is one way enough? – Tomasz Pluskiewicz Jun 20 '16 at 18:41
  • @Tomasz: Two-way would be necessary. – Matt Jun 20 '16 at 19:13

1 Answers1

1

I've almost got it by using Polymer.Templatizer behaviour. Unfortunately it seems that there is some bug or my mistake which prevents updates from parent from being applied to the dynamically created template. I'll raise an issue on GitHub.

<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
<link rel="import" href="paper-button/paper-button.html">
<link rel="import" href="paper-input/paper-input.html">

<dom-module id="my-app">
  <template>
 <paper-input label="global.text" value="{{global.text}}"></paper-input>
 <paper-button raised id="addHeadline" on-tap="addHeadline">Add Headline</paper-button>
 <paper-button raised id="changeText" on-tap="click">Change Text</paper-button>
 <p>global.text: &lt;{{global.text}}&gt;</p>
 
 <template if="true" is="dom-if">
   <div>      
  dom-if: <input type="text" value="{{global.text::input}}" />
   </div>
 </template>
  </template>
  <script>
 Polymer({
   is: "my-app",
   behaviors: [ Polymer.Templatizer ],
   properties: {
  global: {
    value: { text:'i' },
    notify: true
  }
   },
   ready: function() {
  this.count = 0;
  
        // this ensures that global.text is updated when text changes
  this._instanceProps = {
   text: true
  };
   },
   addHeadline: function() {
  
  this.template = document.createElement("template");
  var templateRoot = document.createElement('div');
  templateRoot.innerHTML = `<h1>{{text.text}}</h1><input type="text" value="{{text.text::input}}" />`;
        // you cannot just set innerHTML in <template>
  this.template.content.appendChild(templateRoot);
  
  this.templatize(this.template);
  var clone = this.stamp({
    text: this.global
  });

  // Append to my-app
  Polymer.dom(this.root).appendChild(clone.root);
   },
   click: function() {
  this.set("global.text", "count-" + this.count++);
   },
   _forwardInstanceProp: function(inst, p, val) {
  debugger;
   },
   _forwardInstancePath: function(inst, p, val) {
        // notify parent's correct path when text.text changes
  this.set(p.replace(/^text/, 'global'), val);
   },
   _forwardParentProp: function(prop, value) {
  debugger;
   },
   _forwardParentPath: function(prop, value) {
  debugger;
   }
 });

  </script>
</dom-module>
<my-app></my-app>
Tomasz Pluskiewicz
  • 3,622
  • 1
  • 19
  • 42
  • Hey @tomasz-pluskiewicz good idea. I tried also sth. similar and failed too :) In my try I skipped the templatize and stamp steps and just added a new template. This ended up in the same result. I just guess that the additional element isn't added to the _nodes of the "outer" template and because of that there are no effects triggered for the newly created node. – Matt Jun 20 '16 at 22:16