Databinding in Polymer

送分小仙女□ 提交于 2019-12-11 16:17:17

问题


My Goal

I want to databind the items property shown in this jsBin -- and have the rendered HTML text output match the value shown in the console.

What I expect to see...

When I open this jsBin, in the right pane labeled output, I expect to see the following in the second line of text:

Lorem,Ipsum,foo,1,bar,1,baz,0,qux,0

What I actually see...

Instead, I see:

Lorem,Ipsum,foo,0,bar,0,baz,0,qux,0

But if you click the button labeled Show, and check the console, you will see the following:

console.log
Lorem,Ipsum,foo,1,bar,1,baz,0,qux,0

The two don't match.

Question

How do I update/databind these variables so the output pane matches the console value?

(Please show a working jsBin if possible.)

Code

http://jsbin.com/laxaridawa/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">
</head>
<body>

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

<template>
  <button on-tap="_show">Show</button>
  <div>{{selected}}</div>
  <div>{{items}}</div>
</template>

<script>
  (function(){
    Polymer({
      is: 'x-element',
      properties: {
        items: {
          type: Array,
          notify: true,
          reflectToAttribute: true,
          computed: '_computeItems(selected)',
          value: function() {
            return [['Lorem', 'Ipsum'], ['foo', 0], ['bar', 0], ['baz', 0], ['qux', 0],];
          }
        },
        selected: {
          type: Array,
          notify: true,
          reflectToAttribute: true,
        },
      },
      _computeItems: function(a) {
        var out = this.items,
            selectedLength = a.length,
            i = out.length;
        while(i---1){
          var j = selectedLength;
          while(j--) {
            if(a.indexOf(out[i][0])===-1){
              out[i][1] = 0;
            }
            else if(a.indexOf(out[i][0])>-1){
              out[i][1] = 1;
            }
            else {
              console.log('Error: Undefined index of selected item');
            }
          }
        }
        return out;
      },
      ready: function(){
        this.set('items', this._computeItems(this.seletcted));
      },
      _show: function() {
        console.log('Selected: ' + this.selected);
        console.log('Items: ' + this.items);
      },
    });
  })();

</script>

</dom-module>

<x-element
  selected='["foo","bar"]'
></x-element>

</body>

回答1:


You can't treat one property as computed and have a value. Only one of those at one time.

You don't need to invoke recalculation of a computed property. When the property listed in the arguments of the computed function the computed property is recalculated automatically. In your case every time selected changes.




回答2:


As far as I've found out, the problem is caused by you editing the items array in place.

It would seem, that after running the compute function _computeItems, Polymer evaluates whether the value has changed by comparing references. Since you've reused the array, the reference didn't change and changes aren't propagated further in the framework (both to bindings and other computed properties, see jsBin below).

I've found two ways to make it work:

  1. make a copy of the array and return the copy
  2. manually call notifyPath to notify that the value has changed

Here's a jsBin with example fixes. Replace one of the three lines inside _computeItems with it's commented version and it should work. I've also added a computed property that depends on items, to show that without the fix, that property isn't recalculated properly either.

Edit: I'd like to point out, that this seems to mean that it's perfectly correct to have a property that has both compute and value. Value is simply an initial value, which will immediatly be recalculated because selected's value is set.

WARNING If both items and selected have an initial value and items is computed based on selected, things get hairy - compute may be run before an initial value is set, depending on declaration order.

  1. jsBin When items is first, the order seems to be items-value, selected-value, items-compute and items-compute sees this.items having the initial value.

  2. jsBin When selected is declated first, then selected-value is ran first which triggers items-compute. Now, if items-compute returns undefined, items-value is taken, but if items-compute returns a value, items-value seems to be never used (check by uncommenting code in _computeItems).



来源:https://stackoverflow.com/questions/35172641/databinding-in-polymer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!