Полимерные вложенные шаблоны dom-repeat не обновляются при добавлении элементов в подмассив - PullRequest
1 голос
/ 21 марта 2019

Контекст

Я делаю страницу, которая отображает список предметов. На странице перечислены элементы, самые новые и самые старые, и они классифицируются сначала по годам, а затем по месяцам. Это будет выглядеть примерно так:

2019

Март

  • элемент списка
  • элемент списка 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). Я запрашиваю в базе данных некоторые элементы списка, перебираю каждый элемент и затем добавляю его в соответствующий массив месяцев.

выпуск

Эта страница загружает только первые 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()). Я не уверен, почему это сработает, но я видел, что предложено в этом выпуске Github пост .

Также, если у вас есть лучшее предложение, чем массив лет, который содержит массив месяцев, который содержит массив элементов, тем лучше.

Ответы [ 2 ]

2 голосов
/ 22 марта 2019

Я получил это работает.Он не настолько элегантен или, возможно, настолько идиоматичен для Polymer, насколько это возможно, но он работает, поэтому я делюсь им здесь.

Я создал свойство items, в котором хранятся все элементы.Затем, когда я загружаю новую партию элементов, я помещаю новые элементы в существующий массив элементов и снова перестраиваю весь массив years.

1 голос
/ 30 марта 2019

Из того, что я могу сказать, вы меняете существующий массив, что означает, что Polymer не видит никакой разницы между вашим "измененным" массивом и предыдущим ... потому что они оба являются одним и тем же массивом (ссылки на массивы), ууу!).

Вам нужно либо 1) создать новый массив и позволить ему заменить новый на this.set(), 2) клонировать массив - через JSON.parse(JSON.stringify(arr) - который вы изменили, и this.set() it, 3) Используйте this.splice(), потому что в теории это должно сработать, или 4) сделать то, что вы сделали: сбросьте массив на пустой, а затем замените его на ваш измененный массив.

Подсвойство массиваОбновления в dom-repeat - это проблема, которая исправлена ​​в Polymer 2 и более поздних версиях, поскольку они убрали грязную проверку.


Еще одна небольшая вещь, но не создавайте переменные внутри для циклов.Создание новых переменных внутри цикла 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);
  }
...