Data-binding between nested polymer elements

Ümit picture Ümit · May 7, 2014 · Viewed 12.9k times · Source

Suppose I have two distinct polymer-elements

One should be embedded inside the other using the content placeholder. Is it possible to do data-binding between these two nested polymer-elements ?

I tried, but I can't get it to work: http://jsbin.com/IVodePuS/11/

According to http://www.polymer-project.org/articles/communication.html#binding data-binding between polymer-elements should work (in those examples they were done inside the template tag without using a content placeholder).

Update:

Scott Miles clarified that data-binding only works on the template level.
However in my case I don't know the exact template beforehand but I want to allow the user of my parent-element to specify which child-element it should contain (provided that there are different child-elements.
I think this question is related to this one: Using template defined in light dom inside a Polymer element

I updated the example below to highlight his:

<polymer-element name="parent-element" >
  <template >
    <div>Parent data: {{data1}} </div>
    <content />
  </template>
  <script>
    Polymer('parent-element', {
      data1 : '',
      ready: function() {
        this.data='parent content';
      }
    });

  </script>
</polymer-element>

<polymer-element name="child-element" attributes="data2">
   <template>
    <div>Parent data: {{data2}} </div>
  </template>
  <script>
    Polymer('child-element', {
      data2 : '',
      ready: function() {
      }
    });
  </script>
</polymer-element>

<polymer-element name="child2-element" attributes="data2">
   <template>
    <div>Parent data: {{data2}} </div>
  </template>
  <script>
    Polymer('child2-element', {
      data2 : '',
      ready: function() {
      }
    });
  </script>
</polymer-element>

The user can choose which child-element to embed:

<parent-element data1 = "test">
  <child-element data2="{{data1}}"/>
</parent-element>

<parent-element data1 ="test" >
  <child2-element data2="{{data1}}"/>
</parent-element>

Workaround:

The only workaround I found was to add change watcher and use getDistributedNodes() to get the child element and manually set data2 to data:

<polymer-element name="parent-element" >
  <template >
    <div>Parent data: {{data}} </div>
    <content id="content"/>
  </template>
  <script>
    Polymer('parent-element', {
      data : '',
      ready: function() {
        this.data='parent content';
      },
      dataChanged : function() {
          contents = this.$.content.getDistributedNodes();
          if (contents.length > 0) {
              contents[0].data2 = this.data;
          }
      },
    });

  </script>
</polymer-element>

Answer

Scott Miles picture Scott Miles · May 7, 2014

Polymer data-binding works by attaching a model to a whole subtree.

You wrote:

<parent-element>
  <child-element data2="{{data}}"/>
</parent-element>

this implies a rule that the parentNode provides the binding model. But now imagine you wanted to write:

<parent-element>
  <div>
    <child-element data2="{{data}}"></child-element>
  </div>
</parent-element>

Now you have a problem.

Instead, in Polymer examples, you will notice that the {{}} are (almost always) inside of a template. For example, if I define:

<polymer-element name="host-element" attributes="data" noscript>
<template>
  <parent-element data1="{{data}}">
    <child-element data2="{{data}}"></child-element>
  </parent-element>
</template>
</polymer-element>

Now, I have a model context (host-element) that I can use to bind things together in the entire subtree described by the template.

Note that I don't need attributes="data" for this to work. I added that so host-element exposes data and I can do this:

<host-element data="test"></host-element>  

http://jsbin.com/IVodePuS/15/edit