Search code examples
polymerpolymer-1.0paper-elementsjsbin

Polymer 1.x: Two-way databinding for paper-dropdown-menu


I want to set the paper-dropdown-menu to the value of 'Three' upon loading. I want to do this by data binding the value attribute of the paper-dropdown-menu to a sub property of the element called item.number which is set when registering the element. When I attempt this using the below code, the result I see is that the paper-dropdown-menu displayed value is just blank instead of reading 'Three'.

What code changes will achieve my desired behavior?

Follow these steps to reproduce the problem.

  1. Open this JSBin.
  2. Note the content of the display value of the dropdown menu is blank.
  3. Click the button labeled Click to show item
  4. Observe the console prints:

    [object Object] { number: "Three" }

  5. Understand the above steps demonstrate my desired behavior is not occurring.
  6. Select the number "Four" in the dropdown menu.
  7. Click the button labeled Click to show item
  8. Observe the console prints:

    [object Object] { number: "Four" }

  9. Understand the above step shows one-way data binding is working on the element.

How can I achieve my desired behavior?

http://jsbin.com/loceqayezo/1/edit?html,console,output
<!doctype html>
<head>
  <meta charset="utf-8">
  <base href="https://polygit.org/components/">
  <script src="webcomponentsjs/webcomponents-lite.min.js"></script>
  <link href="polymer/polymer.html" rel="import">
  <link href="paper-dropdown-menu/paper-dropdown-menu.html" rel="import">
  <link href="paper-listbox/paper-listbox.html" rel="import">
  <link href="paper-item/paper-item.html" rel="import">
</head>
<body>

<dom-module id="x-element">

<template>
  <style></style>

  <p>
    <button on-tap="show">Click to show item</button>
  </p>

  <paper-dropdown-menu label="Numbers"
                       value="{{item.number}}">
    <paper-listbox class="dropdown-content">
      <paper-item>One</paper-item>
      <paper-item>Two</paper-item>
      <paper-item>Three</paper-item>
      <paper-item>Four</paper-item>
    </paper-listbox>
  </paper-dropdown-menu>


</template>

<script>
  (function(){
    Polymer({
      is: "x-element",
      properties: {
        item: {
          type: Object,
          notify: true,
          value: function() {
            return {number: "Three"};
          },
        },
      },
      show: function() {
        console.log('item', this.item);
      },
    });
  })();
</script>

</dom-module>

<x-element></x-element>

</body>

Solution

  • Your code doesn't work because value property of <paper-dropdown-menu> is read-only. See the documentation.

    Instead you can bind to <paper-listbox selected>. With minimal changes you will have to bind to dropdown's element index.

    Polymer({
          is: "x-element",
          properties: {
            item: {
              type: Object,
              notify: true,
              value: function() {
                return {number: 2};
              },
            },
          },
          show: function() {
            console.log('item', this.item);
          },
        });
    <!doctype html>
    <head>
      <meta charset="utf-8">
      <base href="https://polygit.org/components/">
      <script src="webcomponentsjs/webcomponents-lite.min.js"></script>
      <link href="polymer/polymer.html" rel="import">
      <link href="paper-dropdown-menu/paper-dropdown-menu.html" rel="import">
      <link href="paper-listbox/paper-listbox.html" rel="import">
      <link href="paper-item/paper-item.html" rel="import">
    </head>
    <body>
    
    <dom-module id="x-element">
    
    <template>
      <style></style>
    
      <p>
        <button on-tap="show">Click to show item</button>
      </p>
    
      <paper-dropdown-menu label="Numbers">
        <paper-listbox class="dropdown-content" 
                       selected="{{item.number}}">
          <paper-item>One</paper-item>
          <paper-item>Two</paper-item>
          <paper-item>Three</paper-item>
          <paper-item>Four</paper-item>
        </paper-listbox>
      </paper-dropdown-menu>
      
    
    </template>
    </dom-module>
    
    <x-element></x-element>
    
    </body>

    To keep the full name in your item you can add an attribute to you selectable elements and use the attrForSelected property of paper-listbox.

    Polymer({
          is: "x-element",
          properties: {
            item: {
              type: Object,
              notify: true,
              value: function() {
                return {number: "Three"};
              },
            },
          },
          show: function() {
            console.log('item', this.item);
          },
        });
    <!doctype html>
    <head>
      <meta charset="utf-8">
      <base href="https://polygit.org/components/">
      <script src="webcomponentsjs/webcomponents-lite.min.js"></script>
      <link href="polymer/polymer.html" rel="import">
      <link href="paper-dropdown-menu/paper-dropdown-menu.html" rel="import">
      <link href="paper-listbox/paper-listbox.html" rel="import">
      <link href="paper-item/paper-item.html" rel="import">
    </head>
    <body>
    
    <dom-module id="x-element">
    
    <template>
      <style></style>
    
      <p>
        <button on-tap="show">Click to show item</button>
      </p>
    
      <paper-dropdown-menu label="Numbers">
        <paper-listbox class="dropdown-content" 
                       selected="{{item.number}}"
                       attr-for-selected="data-item">
          <paper-item data-item="One">One</paper-item>
          <paper-item data-item="Two">Two</paper-item>
          <paper-item data-item="Three">Three</paper-item>
          <paper-item data-item="Four">Four</paper-item>
        </paper-listbox>
      </paper-dropdown-menu>
      
    
    </template>
    </dom-module>
    
    <x-element></x-element>
    
    </body>