是否有惯用的方法来计算Polymer中数组元素的子集?

时间:2014-09-24 09:08:53

标签: arrays polymer idiomatic

我有一个带有一系列对象的模型。对象具有用户可以更新的属性。

在UI的另一部分,我想展示一些关于数组的统计数据;项目总数和设置属性的项目数。

使用单数组而不是对象的示例。单击列表项以切换" a"财产:http://jsfiddle.net/rskqbquL/4/

<polymer-element name="test-cool">
    <template>
        <ol>
            <template repeat="{{item, i in list}}">
                <li on-tap="{{onTap}}" x-index="{{i}}">{{item[0]}}</li>
            </template>
        </ol>
        <p>Total: {{list.length}}</p>
        <p>A:s: {{list | countA}}</p>
    </template>
    <script>
        Polymer("test-cool", {
            list: [["a"], ["ab"], ["ac"], ["d"], ["e"]],

            countA: function(list) {
                var ret = 0;

                list.forEach(function(item) {
                    if (item[0].indexOf("a") >= 0) ++ret;
                });
                return ret;
            },
            onTap: function(e, _, el) {
                var item = el.innerText;
                var index = parseInt(el.getAttribute("x-index"));

                if (item.indexOf("a") >= 0) {
                    this.list[index][0] = item.slice(1);
                } else {
                    this.list[index][0] = "a" + item;
                }

                // Workaround
                this.list = this.list.slice();
            }
        });
    </script>
</polymer-element>

<test-cool></test-cool>

我找不到任何方法来观察数组中所有项的特定属性,因此onTap()中的列表的解决方法是虚拟赋值。

收集有关数组子集的统计信息的惯用聚合物方式是什么?

3 个答案:

答案 0 :(得分:0)

使用过滤器并勾选list(例如1this.list = this.list.slice()) works, but every time the on-tap handlers gets called, the entire DOM list is rendered. Instead, I would create a counterA`变量以跟踪数组长度

此外,而不是使用:

var item = el.innerText;
var index = parseInt(el.getAttribute("x-index"));

您可以直接使用数据模型(docs):

var item = el.templateInstance.model.item;
var index = el.templateInstance.model.i;

解决此问题的一种方法是http://jsbin.com/fitav/1/edit

<p>A:s: {{countA}}</p>

onTap: function(e, detail, el) {
    var item = el.templateInstance.model.item;
    var index = el.templateInstance.model.i;

    this.list[index][0] = this.hasA(item[0])  ? 
                          item[0].slice(1) : "a" + item;

    this.countA = this.filterA();
},
hasA: function(item) {
  return item.indexOf("a") >= 0;
},
listChanged: function() {
  this.countA = this.filterA();
}

答案 1 :(得分:0)

目前的最佳做法是使用观察踢来触发重新计算。 Fwiw,我们通常对这个答案不满意,并正致力于更好的自动化。

开局就是这样描述你的装订:

    <p>A:s: {{list | countA(kick)}}</p>

并且在更改列表项的关键位置,递增kick属性。需要说明的是,kick属性除了触发重新计算外没有任何其他用途。

    kick: 0,
    onTap: function(e) {
      var item = e.target.templateInstance.model.item;
      item[0] = this.toggleA(item[0]);
      this.kick++;
    }

正如我所说,这是一个临时解决方案,直到我们进行更多自动化变更检测或至少提供一个api来踢。

在此全面实施:http://jsbin.com/naboke/5/edit

答案 2 :(得分:0)

这是使用我最近为此目的编写的Polymer元素的解决方案:<observe-array-items><observe-array-items>简化了为数组中的每个项创建/维护PathObserver的过程。

&#13;
&#13;
<script src="//www.polymer-project.org/platform.js"></script>
<link rel="import" href="//www.polymer-project.org/components/polymer/polymer.html">
<link rel="import" href="//rawgit.com/jeffposnick/observe-array-items/master/observe-array-items.html">

<polymer-element name="array-observation">
  <template>
    <observe-array-items array="{{list}}"
                 path="text"
                 on-array-item-changed="{{handleArrayItemChanged}}">
    </observe-array-items>
    
    <ol>
      <template repeat="{{item in list}}">
        <li on-tap="{{handleListTap}}">{{item.text}}</li>
      </template>
    </ol>
    
    <p>
      <input type="text" value="{{newItemText}}">
      <button on-tap="{{handleAddItem}}">Add Item</button>
    </p>

    <p>Total: {{list.length}}</p>
    <p>'A's: {{countOfA}}</p>
  </template>

  <script>
    Polymer({
      countOfA: 0,
      list: null,
      newItemText: 'f',
      
      listChanged: function() {
        // This will be triggered when list is first initialized,
        // and any time an item is added or removed from the array.
        var count = 0;
        
        this.list.forEach(function(item) {
          if (this._hasA(item.text)) {
            count++;
          }
        }.bind(this));
        
        this.countOfA = count;
      },
      
      _hasA: function(str) {
        console.log('checking', str);
        return str.indexOf('a') >= 0;
      },
      
      handleArrayItemChanged: function(e) {
        if (!this._hasA(e.detail.oldValue) && this._hasA(e.detail.newValue)) {
          // If the old value didn't have an 'a' and the new value does, then increment countOfA.
          this.countOfA++;
        } else if(this._hasA(e.detail.oldValue) && !this._hasA(e.detail.newValue)) {
          // If the old value did have an 'a' and the new value doesn't, then decrement countOfA.
          this.countOfA--;
        }
        // Don't do anything for the other cases, since 'a'-ness has stayed the same.
      },

      handleListTap: function(e, _, el) {
        var item = el.templateInstance.model.item;

        if (this._hasA(item.text)) {
          item.text = item.text.slice(1);
        } else {
          item.text = 'a' + item.text;
        }
      },
      
      handleAddItem: function() {
        this.list.push({text: this.newItemText});
      },

      ready: function() {
        this.list = [
          {text: 'a'},
          {text: 'ab'},
          {text: 'ac'},
          {text: 'd'},
          {text: 'e'}
        ];
      }
    });
  </script>
</polymer-element>

<h1>Polymer Demo: Observing Changes to Properties of Items in an Array</h1>
<array-observation></array-observation>
&#13;
&#13;
&#13;

我认为这是解决您尝试做的事情的一种相当惯用的方式,因为它在很大程度上依赖于观察回调来确保相关状态保持最新。您可以直接从代码中的任何位置修改数据,而无需担心忘记调用特定的帮助函数等。