how to bind to the contents?

207 views
Skip to first unread message

aleem....@gmail.com

unread,
Jan 6, 2015, 11:25:05 PM1/6/15
to polym...@googlegroups.com
Hi all,

Sorry for the newbie question but I'm creating my first element. I'm trying to create an element which has a dynamic number of tabs depending on what content is given to the element. The only way I've figured out how to do this is in JS but I have a feeling this isn't the Polymer way, what am I missing? Can you point me to some docs or other elements that will help me get started? 

here's what I have so far:


<code-file-set>
   <a href="#" tabTitle="onelink">onelink</a>
   <a href="#" tabTitle="twolink">twolink</a>
   <a href="#" tabTitle="threelink">threelink</a>
</code-file-set>




<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="/bower_components/core-pages/core-pages.html">
<link rel="import" href="/bower_components/paper-tabs/paper-tabs.html">



<polymer-element name="code-file-set">
  <template>

      <paper-tabs style="max-width:{{tabBarWidth}}px" id="tabs" selected={{selected}}>
      </paper-tabs>

      <core-pages selected="{{selected}}">
        <content id="codecontent" select="a"></content>
      </core-pages>
  </template>

<script>

  Polymer('code-file-set', {
    domReady: function() {
      var codeNodes = this.$.codecontent.getDistributedNodes();

      for (var i = 0; i < codeNodes.length; i++) {
        var name = codeNodes[i].getAttribute('tabTitle');
        var tab = document.createElement('paper-tab');
        tab.innerHTML = name;
        this.$.tabs.appendChild(tab);
      }


      this.selected = 0;
      this.tabBarWidth = codeNodes.length * 250;
    },
  });
</script>
</polymer-element>

This works, but it seems ugly. Namely, can creating the tabs not be done in JS but in a more declarative way in the HTML (notice that I create one tab per <a> element found in the content). Similarly for the width of the max width of the paper tabs.

Dennis Coldwell

unread,
Jan 7, 2015, 3:01:56 AM1/7/15
to polym...@googlegroups.com, aleem....@gmail.com
Hi Aleem,

This looks like something that could be solved quite easily with template binding, have you seen that in action yet? The docs have some good examples:

I'm guessing that set of <a> tags is dynamic and coming from some external source? If so you can use the "repeat" attribute in Polymer's template binding to help create your <paper-tab> elements more declaratively. No javascript required!

For your max-width logic, I'd need to understand a bit more about what you are trying to accomplish. It seems to me that you should be able to get what you want with CSS/Flexbox and shouldn't need to hardcode max-widths. 

Hope that helps you. Good luck!
--Dennis

aleem....@gmail.com

unread,
Jan 7, 2015, 3:31:10 AM1/7/15
to polym...@googlegroups.com, aleem....@gmail.com
Thanks for taking the time to respond Dennis. Inline:

On Wednesday, January 7, 2015 12:01:56 AM UTC-8, Dennis Coldwell wrote:
Hi Aleem,

This looks like something that could be solved quite easily with template binding, have you seen that in action yet? The docs have some good examples:

I'm guessing that set of <a> tags is dynamic and coming from some external source?

The list of <a>'s is coming from whomever decides to use my custom element code-file-set

The way I imagined people using this was that they use the code-file-set element and put <a>'s inside. My code-file-set would render those <a>'s as seperate "pages" in a core-pages and create tabs to allow switching between the pages. Does that make sense?
 
If so you can use the "repeat" attribute in Polymer's template binding to help create your <paper-tab> elements more declaratively. No javascript required!

I'm not following how the "repeat" attribute helps. From my understanding, lets say I put something like this in code-file-set:

      <template repeat="{{s in salutations}}">
        <li>{{s.what}}: <input type="text" value="{{s.who}}"></li>
      </template>


This is from the polymer docs. Isn't salutations a JS object thats passed into my custom element as an attribute? How would I make salutations or some similar variable refer to all of the <a>'s that are the content of my code-file-set?

I'm probably misunderstanding what you're saying, any chance you could explain with a code snippet?

Dennis Coldwell

unread,
Jan 7, 2015, 10:05:59 PM1/7/15
to polym...@googlegroups.com, aleem....@gmail.com
Oh, my apologies Aleem! I thought you were pulling some arbitrary set of links from a datastore or something. Sorry that I misread your intent. 

You can still use the Polymer's template data binding in this case, it cleans up the javascript and makes the custom element more readable (IMHO), here's the code snippet to show what I mean:

<link rel="import" href="/assets/bower_components/polymer/polymer.html">
<link rel="import" href="/assets/bower_components/core-pages/core-pages.html">
<link rel="import" href="/assets/bower_components/paper-tabs/paper-tabs.html">

<polymer-element name="code-file-set">
  <template>

      <paper-tabs style="max-width:{{tabBarWidth}}px" id="tabs" selected={{selected}}>
        <template repeat="{{ tab in tabNames }}">
          <paper-tab>{{tab}}</paper-tab>
        </template>
      </paper-tabs>

      <core-pages selected="{{selected}}">
        <content id="codecontent" select="a"></content>
      </core-pages>
  </template>

<script>

  Polymer('code-file-set', {
    domReady: function() {
      var codeNodes = this.$.codecontent.getDistributedNodes();
      this.tabNames = [];

      for (var i = 0; i < codeNodes.length; i++) {
        this.tabNames.push(codeNodes[i].getAttribute('tabTitle'));
      }

      this.selected = 0;
      this.tabBarWidth = codeNodes.length * 250;
    },
  });
</script>
</polymer-element>

You can see that I've replaced your javascript createElement and appendChild lines with a simple push to an array which can be used by Polymer's template binding. Does that make sense? I like this approach because I can see exactly what's being created just by looking at the shadow dom.

A slight follow-up question for you though...why are you creating a custom element at all? Are you trying to hide Polymer implementation details? It's very common/straightforward to use the paper-tabs/core-pages combo directly (in fact it is a direct example on the Polymer docs: https://www.polymer-project.org/docs/elements/paper-elements.html#paper-tabs). I'm not sure that I see what you buy by wrapping this into a custom element. Why reinvent the wheel?

Anyway, hope that is helpful. Sorry for the long delay in response. I only get time to check out the polymer list after the work day is finished :)
--Dennis


On Tuesday, January 6, 2015 8:25:05 PM UTC-8, aleem....@gmail.com wrote:

Aleem Mawani

unread,
Jan 8, 2015, 1:59:53 AM1/8/15
to Dennis Coldwell, polym...@googlegroups.com
Thanks so much! That was very helpful.

One follow up question, this does not handle the case where more content nodes are added after the element is initialized. Tried to find the answer to this in the docs to no success.

As for the question of what does creating this custom element buy me, you might be right in that there doesn't seem to b huge benefits in this case. The way I posted the code had some simplifications to what I'm doing and I'd like to encapsulate the extra functionality in my custom element. 

Even without that extra functionality I might still do it, as I'd be using this custom element many times on a single page and its half the lines of markup and easier to read when encapsulated in the custom element.

Arthur Evans

unread,
Jan 8, 2015, 12:10:07 PM1/8/15
to Aleem Mawani, Dennis Coldwell, polymer-dev
Hi Aleem,

To find out when your custom element's (light DOM) children are manipulated, you can use a mutation observer. Polymer provides a convenience method for setting this up, described here:


You can access the children all the usual ways, but if you're specifically looking for the children that get distributed through your insertion point (<content> element), the content element provides a getDistributedNodes() method. This is discussed in the FAQ:


Thanks,
Arthur


Follow Polymer on Google+: plus.google.com/107187849809354688692
---
You received this message because you are subscribed to the Google Groups "Polymer" group.
To unsubscribe from this group and stop receiving emails from it, send an email to polymer-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/polymer-dev/CAApOkstqnapfejU6Rsuh%3DfcuQmu3SH40MuEX2bmM-cn9MtZU%3DA%40mail.gmail.com.

For more options, visit https://groups.google.com/d/optout.

Aleem Mawani

unread,
Jan 8, 2015, 2:05:19 PM1/8/15
to Arthur Evans, Dennis Coldwell, polymer-dev
That worked great. Thanks so much all for the newbie help!
Reply all
Reply to author
Forward
0 new messages