Дубликаты ключей в Vue v-для L oop при сортировке таблицы - PullRequest
0 голосов
/ 10 марта 2020

My Vue приложение извлекает данные из Firestore, используя vuefire .

Я импортирую данные из коллекции 'lines' следующим образом:

firestore() {
  return {
    lines: db.collection("lines")
  }
}

Каждая запись имеет идентификатор, сгенерированный в Firestore, который я затем использую в качестве v-for l oop, например:

<thead>
  <tr>
    <th>Code</th>
    <th @click="sort_string(lines,'name')"> Name</th>
    <th>Quantity</th>
  </tr>
</thead>
<tbody v-for="line in lines" :key="line.id">
  <tr>
    <td>{{line.code}}</td>
    <td>{{line.name}}</td>
    <td>{{line.quantity}}</td>
    <button @click="pick_one(line)">+1</button>
    ...

In, имеет метод pick_one, который напрямую изменяет количество в Firestore:

pick_one(line) {

  const new_quantity = line.quantity + 1;      
  db
    .collection("lines")
    .doc(line.id)
    .update({ quantity: new_quantity });
}

Все это прекрасно работает до I sort() базового массива (' lines ').

Если я сортирую таблицу и затем вызываю функцию pick_one Я получаю ошибку дублирующегося ключа:

[Vue warn]: Duplicate keys detected: 'RaTIINFWTQxHQPyRmfsQ'. This may cause an update error.

Я могу только предположить, что это как-то связано с тем, как Vuefire обрабатывает update() вызовы Поскольку сортировка массива не вызывает этой проблемы, обновление только строки в массиве во время сортировки.

Моя функция сортировки (метод vue) выглядит следующим образом:

sort_string(table, column) {
  console.log("sorting")
  this.sort_toggle = -this.sort_toggle;

  return table.sort((a, b) => {
    if (
      a[column].toString().toUpperCase() <
      b[column].toString().toUpperCase()
    ) {
      return -this.sort_toggle;
    }
    if (
      a[column].toString().toUpperCase() >
      b[column].toString().toUpperCase()
    ) {
      return this.sort_toggle;
    }
    return 0;
  });
},

Есть ли способ избежать такого поведения?

1 Ответ

0 голосов
/ 11 марта 2020

Комментарий Фила дал ключ к этому поведению - в том, что функция sort() работает с базовыми данными, а не с копией.

Я изменил свой шаблон так, что v-for теперь зацикливается вычисляемый массив, который можно отсортировать с помощью (слегка измененной) функции.

Функция сортировки теперь использует slice() для создания копии базового массива:

computed: {
  sorted_lines() {
    return sort_string(lines, this.sort_column) // name of the column/filed to sort by
  }

Функция sort_string теперь выглядит так (с добавлением slice()

sort_string(table, column) {
  console.log("sorting")
  //this.sort_toggle = -this.sort_toggle; // moved elsewhere

  return table.slice().sort((a, b) => { // slice() then sort()
  if (
    a[column].toString().toUpperCase() <
    b[column].toString().toUpperCase()
  ) {
    return -this.sort_toggle;
  }
  if (
    a[column].toString().toUpperCase() >
    b[column].toString().toUpperCase()
  ) {
    return this.sort_toggle;
  }
  return 0;
});
},
...