【问题标题】:Is there an idiomatic way to count a subset of array elements in Polymer?有没有一种惯用的方法来计算 Polymer 中数组元素的子集?
【发布时间】:2014-11-18 17:02:22
【问题描述】:

我有一个包含对象数组的模型。对象具有用户可以更新的属性。

在 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() 中对列表进行虚拟分配。

什么是惯用的 Polymer 收集有关数组子集的统计信息的方法?

【问题讨论】:

    标签: arrays polymer idioms


    【解决方案1】:

    使用过滤器并标记list(例如 1this.list = this.list.slice()) works, but every time theon-taphandlers gets called, the entire DOM list is rendered. Instead, I would create acounterA` 变量来跟踪数组长度。

    另外,不要使用:

    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();
    }
    

    【讨论】:

      【解决方案2】:

      当前的最佳实践是使用观察踢来触发重新计算。 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

      【讨论】:

        【解决方案3】:

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

        <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>

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-07-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-02-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多