Let Me Tink About It
Let Me Tink About It

Reputation: 16102

Polymer 1.x: Databinding to sub-properties

I want to databind to an object's sub-property.

I expect to see my output change in response to selecting different menu items. But instead, I see no response in the output.

To recreate the problem, follow these steps.

  1. Open this jsBin.
  2. Notice both outputs (Dom-repeat and Computed) correctly reflect the selected menu items "bar" and "qux".
  3. Select (or de-select) a menu item.
  4. Notice Dom-repeat responds appropriately.
  5. ❌ Notice Computed does not respond at all.

What code makes Computed respond to changes in the sub-property ob.selected?

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

<x-element></x-element>

<dom-module id="x-element">
<template>
  <style>
    iron-selector > * {
      padding: 8px;
    }
    .iron-selected {
      background-color: blue;
      color: white;
    }
  </style>

  <br><br>
  <paper-menu multi attr-for-selected="name" selected-values="{{ob.selected}}">
    <paper-item name="foo" >Foo</paper-item>
    <paper-item name="bar" >Bar</paper-item>
    <paper-item name="baz" >Baz</paper-item>
    <paper-item name="qux" >Qux</paper-item>
    <paper-item name="quux">Quux</paper-item>
  </paper-menu>
  <p>
    <strong>Dom-repeat</strong>:
    <template is="dom-repeat" items="{{ob.selected}}">
      <span>[[item]] </span>
    </template>
  </p>
  <p><strong>Computed</strong>: {{str}}</p>
</template>
<script>
  Polymer({
    is: 'x-element',
    properties: {
      ob: {
        type: Object,
        value: function() {
          return {
            selected: ['bar', 'qux'],
          }
        }
      },
      str: {
        type: String,
        computed: '_computeStr(ob)',
      }
    },
    _computeStr: function(temp) { // Doesn't respond to changes in temp.selected
      return temp.selected.join(', ');
    },

  });
</script>
</dom-module>
</body>

Upvotes: 0

Views: 129

Answers (1)

Scott Miles
Scott Miles

Reputation: 11027

It's important to understand ​object identity​. Today, Polymer considers the value of an Object to be it's identity. If x == 2, and I set x=4, x has changed value. If ob = {foo:3}, and I set ob.foo = 4, ob has ​not​ changed value (it's identity hasn't changed) and this change will not trigger an observation of ob.

Instead, we can observe ob.foo directly, or all subproperties of ob via ob.* or, if it's an array, observe the length of ob (ob.length). Something like this will work, for example:

     str: {
       type: String,
       computed: '_computeStr(ob, ob.*)',
     }
   },
   _computeStr: function(temp, info) {    
      return temp.selected.join(', ');
   },

this works because I've asked to be notified if ​subproperties of ob​ change ... this is ob.* The info returned for an observation of ob.* has information on it about what happened to ob.

Upvotes: 4

Related Questions