如何在Polymer中强制进行模板更新?

时间:2016-05-20 08:30:02

标签: javascript html5 templates polymer

如何在聚合物中显示dom-repeat模板中现有项目的更改?

我尝试了所有我能想到的,我可以在聚合物文档或网络中找到。但没有任何作用。下面你会找到一个使用小列表的html页面,当你点击更改按钮时,会尝试将列表中的一个条目更改为另一个值。但唯一可以改变更改按钮旁边列表中项目的是注释掉的行。所有其他行尝试它,但失败。

据我所知,重新渲染模板是一项耗时的任务,只有在必要时才会发生,并且聚合物会尽可能地避免使用它。但为什么我不能(从代码的角度来看,他们的世界之神^^)有意强制渲染?

创建一个完整的新对象,从列表中删除旧项目并插入新对象(这就是注释行所做的)的方法是一种解决方法,但当项目更复杂时,这是一项非常大的工作并且具有甚至不显示的属性或数组。

我缺少什么?我没有尝试过什么?如果有人能告诉我我能做些什么来实现这样一个(从我的观点来看)简单而且非常普遍的任务,我会很高兴。

编辑(已解决): Tomasz Pluskiewicz的解决方案部分成功。但我更新了代码以显示我当前的问题。项目的名称使用方法格式(...)绑定。单击按钮时,该项目将从列表中删除。这很好用。但是如果你删除列表的最后一项,那么列表中的新最后一项应该得到名称" Last"。当名称直接绑定到属性名称时,这也有效。但如果我想对名称进行一些格式化(例如用#围住它),则不会更新此项目的显示。

EDIT2(部分解决): 下一个不起作用的示例发生在调用显示值的方法内部的值发生更改时。如果多次单击更改按钮,则可以在示例中看到此信息。它会增加内部计数器,相应的文本将显示此值。但这只适用于柜台的第一次更换。后续点击不会再次更改显示。显示屏显示第一次单击后计数器的值。但是,如果单击另一个更改按钮,则此按钮前面的文本显示增加的计数器值。但也只有一次。它也不会显示后续点击的变化。 notifyPath方法似乎检查值是否已更改,但是没有考虑在用于显示值的方法内部,可能已更改某些内容以另一种方式显示数据。

我在此示例中包含了部分解决方案。如果被调用的方法的参数在方法中的某些内容发生更改时发生更改,则将执行更新。这可以在与参数displayEnforcer - format(item.name,displayEnforcer)绑定的第二个变量中看到。每次更改计数器时,此变量都设置为随机值。这会触发显示更新。

但这是一个非常奇怪的解决方案,不应该是必要的。如果有人能够更好地解决这个问题,那将会很棒。

<link rel="import" href="components/bower_components/polymer/polymer.html">
<link rel="import" href="components/bower_components/paper-button/paper-button.html">
<dom-module id="polymer-test">
  <template>
    <table>
      <template id="tpl" is="dom-repeat" items="{{list}}">
        <tr>
          <td>{{item.id}} - {{format(item.name)}}- {{format(item.name,displayEnforcer)}}</td>
          <td><paper-button raised on-tap="tapDelete">delete</paper-button></td>
          <td><paper-button raised on-tap="tapChange">change</paper-button></td>
        </tr>
      </template>
    </table>
  </template>
</dom-module>
<script>
  Polymer(
  {
    is: "polymer-test",
    properties:
    {
      count: {type: Number, value:0}
     ,list: {type: Array, value: [{id:0,name:"First"}
                                 ,{id:1,name:"Second"}
                                 ,{id:2,name:"Third"}
                                 ,{id:3,name:"Fourth"}
                                 ,{id:4,name:"Fifth"}
                                 ,{id:5,name:"Last"}
                                 ]}
     ,displayEnforcer: {type:Number,value:Math.random()}
    },
    format: function(name,dummy)
    {
      return "#" + name + " - " + this.count + "#";
    },
    tapChange: function(e)
    {
      this.count++;
      this.displayEnforcer = Math.random();
      this.notifyPath("list." + (e.model.index) + ".name","changed");
    },
    tapDelete: function(e)
    {
      if(this.list.length == 1)
        return;
      this.splice("list",e.model.index,1);
      if(this.list.length > 0)
        this.list[this.list.length-1].name = "Last";
      this.notifyPath("list." + (this.list.length-1) + ".name",this.list[this.list.length-1].name);
    }
  });
</script>

1 个答案:

答案 0 :(得分:1)

您可以使用notifyPath刷新单个列表元素属性的绑定:

tapChange: function(e) {
  this.notifyPath('list.' + e.model.index + '.name', 'changed');
}

请参阅:https://github.com/Polymer/polymer/issues/2068#issuecomment-120767748

这种方式不会重新渲染整个转发器,只是更新必要的数据绑定节点。

修改

您的format函数未获得更新,因为它不使用作为项目名称的通知路径。删除元素时,即使实际项目发生更改,呈现的转发器中该元素的索引也不会更改。换句话说,当你删除第五个元素时,索引4仍然是4。

作为一种变通方法,您可以将item.name添加到format调用,以便在通知该路径时刷新它:

<td>{{item.id}} - {{format(index, item.name)}}</td>

您甚至不必在示例中使用该值。重新评估绑定就足够了。