2

First, I'm loving Polymer. I'm not proficient in javascript, and I don't fully understand all the shadow-DOM stuff that's going on. But I take it that Polymer is under development for people like me (non-full-time coders who need to build websites quickly and programmatically by plugging simple pieces together). It's lots of fun, and once I understand how something in it works, it's really lovely.

My latest attempt to build a site / app involves a lot of menu and submenu items connected to core-pages. I love the idea that I can just connect a menu item id with a div id inside core-pages and have that work. And when I do it with just menu items and hand-coded ids, it works perfectly. But when I add in core-submenu and template repeat generated items and pages with matching ids, for some reason that is probably obvious to others, it doesn't.

My question: Does submenu/pages require scripting, or am I doing something wrong with my polymer tags? If scripting is required, I'd love some pointers to resources for beginners. I've had a look at the spa.html demo, but it doesn't include submenus. Any tips?

Right now, the core of my code looks like this: http://jsbin.com/xuzezelumeje/1/edit

<script src="http://www.polymer-project.org/platform.js"></script>
<link rel="import" href="http://www.polymer-project.org/components/core-scaffold/core-scaffold.html">
<link rel="import" href="http://www.polymer-project.org/components/core-header-panel/core-header-panel.html">
<link rel="import" href="http://www.polymer-project.org/components/core-menu/core-menu.html">
<link rel="import" href="http://www.polymer-project.org/components/core-menu/core-submenu.html">
<link rel="import" href="http://www.polymer-project.org/components/core-item/core-item.html">
<link rel="import" href="http://www.polymer-project.org/components/core-pages/core-pages.html">

<polymer-element name="my-app">
  <template>

    <core-scaffold>
      <core-header-panel navigation flex mode="seamed">
        <core-toolbar></core-toolbar>

          <core-menu selected="{{selected}}" valueattr="id" theme="core-light-theme">
            <template repeat="{{item in items}}">
              <core-submenu icon="visibility" label="{{item.year}}">
                <template repeat="{{office in item.offices}}">
                  <core-item id="{{office}} {{item.year}}" label="{{office}}"></core-item>
                </template>
              </core-submenu>
            </template>
          </core-menu>

        </core-header-panel>
        <div tool>DC Campaign Finance Watch</div>

        <core-pages selected="{{selected}}" valueattr="id">
          <template repeat="{{item in items}}">
            <template repeat="{{office in item.offices}}">
              <div id="{{office}} {{item.year}}">{{item.year}} {{office}}</div>
            </template>
          </template>
        </core-pages>

  </template>

  <script>
    Polymer({
      ready: function() {
        this.items = [
    {
        "offices": [
            "Mayor",
            "Council Chairman",
            "Council At-Large",
            "etc"
        ],
        "year": "2014"
    },
    {
        "offices": [
            "Council At-Large"
        ],
        "year": "2013"
    },
    {
        "offices": [
            "Council Chairman",
            "Council At-Large",
            "etc"
        ],
        "year": "2012"
    },
    {
        "offices": [
            "Council At-Large",
            "School Board Ward 4",
            "School Board Ward 8"
        ],
        "year": "2011"
    },
    {
        "offices": [
            "Mayor",
            "Council Chairman",
            "etc"
        ],
        "year": "2010"
    }
];
      }
    });
  </script>
</polymer-element>

<my-app></my-app>

1 Answer 1

4

Great to hear that you're enjoying Polymer! There are a few aspects of your code that need some modification, but I think you're almost there. Here's some advice on how to get things working as expected—it's just one way of doing things, and I'm sure there are other solutions, too.

  • You're not using valid values for your ids. ids shouldn't contain spaces, and they should be unique within your element (i.e. don't assign a <core-item> and a <div> the same id). I modified your code to pass your data through a Polymer filter function to replace the spaces with - characters, and to use the prefix page- in front of the id you're assigning your page <div>s.
  • <core-menu> will, by default, treat tapping on a <core-submenu> as if you had selected that submenu, even though you really want only taps on your <core-item> to trigger a selection. Writing a custom on-core-select handler gives you the flexibility to ignore submenu selections, as well as prepend the page- prefix to the selectedPageId used in <core-pages>.
  • This isn't a big deal, but wrapping your page in a throwaway <my-app> Polymer element is unnecessary. When you're writing a web app that consumes Polymer elements but isn't meant to be a reusable Polymer element itself, an alternative to a Polymer wrapper is to use <template is="auto-binding">. You can do pretty much everything within a <template is="auto-binding"> that you could do within a Polymer element's <template>. There's more information in this blog post.

You can see a runnable example of your modified code below:

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
    <title>Polymer SPA</title>

    <script src="//www.polymer-project.org/platform.js"></script>
    <link rel="import" href="//www.polymer-project.org/components/core-scaffold/core-scaffold.html">
    <link rel="import" href="//www.polymer-project.org/components/core-header-panel/core-header-panel.html">
    <link rel="import" href="//www.polymer-project.org/components/core-menu/core-menu.html">
    <link rel="import" href="//www.polymer-project.org/components/core-menu/core-submenu.html">
    <link rel="import" href="//www.polymer-project.org/components/core-item/core-item.html">
    <link rel="import" href="//www.polymer-project.org/components/core-pages/core-pages.html">
  </head>

  <body unresolved fullbleed>
    <template is="auto-binding" id="page-template">
      <core-scaffold theme="core-light-theme">
        <core-header-panel navigation flex mode="seamed" theme="core-light-theme">
          <core-toolbar theme="core-dark-theme"></core-toolbar>
          <core-menu theme="core-light-theme" on-core-select="{{handleSelect}}">
            <template repeat="{{item in items}}">
              <core-submenu icon="visibility" label="{{item.year}}">
                <template repeat="{{office in item.offices}}">
                  <core-item id="{{ office + '-' + item.year | replaceSpaces }}" label="{{office}}"></core-item>
                </template>
              </core-submenu>
            </template>
          </core-menu>
        </core-header-panel>
        <div tool>{{title}}</div>
        <core-pages selected="{{selectedPageId}}" valueattr="id">
          <template repeat="{{item in items}}">
            <template repeat="{{office in item.offices}}">
              <div id="page-{{ office + '-' + item.year | replaceSpaces }}">{{item.year}} {{office}}</div>
            </template>
          </template>
        </core-pages>
      </core-scaffold>
    </template>
  
    <script>
    	var template = document.querySelector('#page-template');
      template.title = 'DC Campaign Finance Watch';

      template.replaceSpaces = function(str) {
      	return str.replace(/\s/g, '-');
    	},
        
      template.handleSelect = function(e) {
        if(e.detail.isSelected && e.detail.item.localName == 'core-item') {
          this.selectedPageId = 'page-' + e.detail.item.id;
        }
      },
        
      template.items = [
        {
          "offices": [
              "Mayor",
              "Council Chairman",
              "Council At-Large",
              "Council Ward 1",
              "Council Ward 3",
              "Council Ward 5",
              "Council Ward 6",
              "Attorney General",
              "School Board Ward 1",
              "School Board Ward 3",
              "School Board Ward 5",
              "School Board Ward 6",
              "School Board Ward 8",
              "US Representative",
              "US Senator",
              "Alternate Democratic National Committeeman",
              "Alternate Democratic National Committeewoman",
              "At-Large DC Democratic State Committee",
              "Democratic National Committeeman",
              "Democratic National Committeewoman",
              "Ward 3 DC Democratic State Committee",
              "Ward 6 DC Democratic State Committee",
              "Ward 1 DC Democratic State Committee"
          ],
          "year": "2014"
        },
        {
          "offices": [
              "Council At-Large"
          ],
          "year": "2013"
        },
        {
          "offices": [
              "Council Chairman",
              "Council At-Large",
              "Council Ward 2",
              "Council Ward 4",
              "Council Ward 5",
              "Council Ward 7",
              "Council Ward 8",
              "School Board At-Large",
              "School Board Ward 2",
              "School Board Ward 7",
              "School Board Ward 8",
              "US Senator",
              "Democratic Delegates",
              "Republican National Committeewoman",
              "Republican National Committeeman"
          ],
          "year": "2012"
        },
        {
          "offices": [
              "Council At-Large",
              "School Board Ward 4",
              "School Board Ward 8"
          ],
          "year": "2011"
        },
        {
          "offices": [
              "Mayor",
              "Council Chairman",
              "Council At-Large",
              "Council Ward 1",
              "Council Ward 3",
              "Council Ward 5",
              "Council Ward 6",
              "School Board Ward 1",
              "School Board Ward 3",
              "School Board Ward 5",
              "School Board Ward 6",
              "US Representative"
          ],
          "year": "2010"
        }
      ];
    </script>
  </body>
</html>

1
  • Wow -- thank you for that comprehensive answer and for the functional code! I can now see why filters are so much more common in everyone else's code than in mine. I also see how the on-core-select works, and that's very nice. I was afraid I'd have to become proficient in all the ins and outs of flatiron, but the js you provided is reassuringly simple. Many thanks!
    – Don
    Commented Oct 3, 2014 at 0:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.