将项目添加到子数组时,聚合物嵌套的dom-repeat模板不会更新

时间:2019-03-21 20:00:07

标签: polymer

上下文

我正在制作一个显示项目列表的页面。该页面列出了最新到最旧的项目,并按年份和月份先对其进行分类。看起来类似于以下示例:

2019

三月

  • 列表项
  • 列出项目2

2月

  • 列出项目3

2018

十月

  • 列出项目4
  • 列出项目5
  • 列出项目6

可能

  • 列出项目7

HTML的简化版本是:

<template is="dom-repeat" items="{{years}}" as="year">
    <span>[[year.name]]</span>
    <div id="same-year-items>
        <template is="dom-repeat" items="{{year.months}}" as="month">
            <span>[[month.name]]</span>
            <div id="same-month-items">
                <template is="dom-repeat" items="{{month.items}}" as="item">
                    <custom-list-item item="{{item}}"></custom-list-item>
                </template>
            </div>
        </template>
    </div>
</template>

在Javascript文件中,我定义了years数组属性。 years中的每年包含一个months数组,months中的每个月份包含一个items数组(请参阅dom-repeat元素)。我在数据库中查询一些列表项,遍历每个项,然后将其添加到相应的month数组中。

问题

此页面仅加载前n个项目。我想在底部有一个“加载更多”按钮,该按钮可以加载接下来的n个项目。 (是的,我知道。无限滚动可能会更好-稍后会出现。即使我使用无限滚动,我仍然会有我要描述的问题。)

当我加载更多项目时,页面不会更新以显示新项目。我知道Polymer对于如何绑定数据非常特别,尤其是当它涉及子属性时。这是Javascript的简化版本,用于将新项目设置为数组:

setItems: function(newItems) {
  var tempYearsArray = [];
  for (var i = 0, i < this.years.length; i++) {
    tempYearsArray.push(this.years[i]);
  }
  
  this.set('years', []);
  
  for (var j = 0; j < newItems.length; j++) {
    var item = newItems[j];
    this.setMonthAndYear(item, tempYearsArray);
  }
  
  this.set('years', tempYearsArray);
}

setMonthAndYear: function(item, tempYearsArray) {
  var itemDate = new Date(item.lastModified);
  var currentYear = itemDate.getFullYear();
  var monthIndex = itemDate.getMonth();
  var monthName = this.monthNames[monthIndex];
  var newYear = true;
  var newMonth = true;
  for (var i = 0; i < tempYearsArray.length; i++) {
    var year = tempYearsArray[i];
    if (currentYear === year.name) {
      newYear = false;
      for (j = 0, j < year.months.length; j++) {
        var month = ref[j];
        if (monthName === month.name) {
          month.items.push(item);
          newMonth = false;
          break;
        }
      }
      if (newMonth) {
        var month = {
          items: [item],
          name: monthName
        };
        year.months.push(month);
      }
      break;
    }
  }
  if (newYear) {
    var month = {
      items: [item],
      name: monthName
    };
    year = {
      name: currentYear,
      months: [month]
    };
    return tempYearsArray.push(year);
  }
}

我可以看到years具有新项目,但是页面仍未呈现它们。我读过其他有类似问题的文章,这是我想到this.set('years', [])和临时数组的地方。我也尝试过做this.notifyPath('year.months', year.months.slice())this.notifyPath('month.items', month.items.slice())之类的事情。我不确定为什么这行得通,但是我在this Github issues post中看到了建议。

另外,如果您的建议比Years数组更好,那么它更好。

2 个答案:

答案 0 :(得分:2)

我知道了。对于Polymer来说,它不那么优雅,或者也许不是惯用的,但是它可以工作,所以我在这里分享。

我创建了一个items属性,用于存储所有项目。然后,当我加载一批新项目时,将新项目推到现有的项目数组中,然后再次重建整个years数组。

答案 1 :(得分:1)

据我所知,您正在更改现有数组,这意味着Polymer看不到您“已更改”的数组与上一个数组之间的任何区别……因为它们都是同一数组(数组引用) ,是的!)。

您需要1)创建一个新数组,并用this.set()替换新数组,2)通过JSON.parse(JSON.stringify(arr)复制并修改this.set()该数组,3)使用this.splice()是因为从理论上讲,它应该起作用,或者4)做您所做的事情:用一个空的数组重置数组,然后用修改后的数组替换。

dom-repeat中的数组子属性更新是在Polymer 2及更高版本中已解决的问题,因为它们删除了脏检查。


另一件事,但不要在for循环内创建变量。在for循环内创建新变量,而不是在外部创建一个然后在循环内重复使用的变量,这是最小的时间损失。

    // Your code
  for (var j = 0; j < newItems.length; j++) {
    var item = newItems[j];
    this.setMonthAndYear(item, tempYearsArray);
  }

    // My suggestion
  var item;

  for (var j = 0; j < newItems.length; j++) {
   item = newItems[j];
   this.setMonthAndYear(item, tempYearsArray);
  }