epicmaxco / vuestic-ui

Vuestic UI is an open-source Vue 3 component library designed for rapid development, easy maintenance, and high accessibility. Maintained by Epicmax (@epicmaxco).
https://vuestic.dev
MIT License
3.52k stars 340 forks source link

data table expandable row duplicates unexpectedly #4421

Closed ionutrifan closed 6 days ago

ionutrifan commented 2 weeks ago

Vuestic-ui version: 1.10.3

Description

When you combine data table expandable rows with data table filtering or virtual scrolling, the same expandable row is rendered multiple times because of duplicate keys. The following warning is triggered:

Duplicate keys found during update:"table-row_20"Make sure keys are unique. at at <VaInnerLoadingaria-live="polite"style=[object Object]loading=false ...> at <VaVirtualScrollerclass="va-data-table"style=[object Object]itemSize=0 ...> at <VaDataTableitems=[object Object],[object Object],[object Object],[object Object],[object Object]columns=[object Object],[object Object],[object Object],[object Object]filter="c">

Reproduction

You can reproduce this in the playground by adding filtering to the provided expandable rows example. Click to expand the row and then filter it. Image 08 11 2024 at 10 07

<template>
  <VaInput v-model="filter"/>
  <VaDataTable
    :items="items"
    :columns="columns"
    :filter="filter"
  >
    <template #cell(actions)="{ row, isExpanded }">
      <VaButton
        :icon="isExpanded ? 'va-arrow-up': 'va-arrow-down'"
        preset="secondary"
        class="w-full"
        @click="row.toggleRowDetails()"
      >
        {{ isExpanded ? 'Hide': 'More info' }}
      </VaButton>
    </template>

    <template #expandableRow="{ rowData }" >
      <tr :key="rowData.username">
      <div class="flex gap-2" :key="rowData.username">
        <VaAvatar :src="`https://randomuser.me/api/portraits/men/${rowData.id}.jpg`" />
        <div class="pl-2">
          <div class="flex gap-1">
            <span>{{ rowData.name }}</span>
            <span class="va-link">@{{ rowData.username }}</span>
          </div>
          <div class="flex items-center">
            <VaIcon size="small" name="phone" color="secondary" class="mr-2" />
            <span>{{ rowData.phone }}</span>
          </div>
          <div class="flex items-center">
            <VaIcon size="small" name="email" color="secondary" class="mr-2" />
            <span>{{ rowData.email }}</span>
          </div>
          <div class="flex items-center">
            <VaIcon size="small" name="language" color="secondary" class="mr-2" />
            <span class="va-link">{{ rowData.website }}</span>
          </div>
        </div>
      </div>
      </tr>
    </template>
  </VaDataTable>
</template>

<script>
import { defineComponent } from "vue";

export default defineComponent({
  data() {
    const items = [
      {
        id: 1,
        name: "Leanne Graham",
        username: "Bret",
        email: "Sincere@april.biz",
        phone: "1-770-736-8031",
        website: "hildegard.org",
      },
      {
        id: 2,
        name: "Ervin Howell",
        username: "Antonette",
        email: "Shanna@melissa.tv",
        phone: "010-692-6593",
        website: "anastasia.net",
      },
      {
        id: 3,
        name: "Clementine Bauch",
        username: "Samantha",
        email: "Nathan@yesenia.net",
        phone: "1-463-123-4447",
        website: "ramiro.info",
      },
      {
        id: 4,
        name: "Patricia Lebsack",
        username: "Karianne",
        email: "Julianne.OConner@kory.org",
        phone: "493-170-9623",
        website: "kale.biz",
      },
      {
        id: 5,
        name: "Chelsey Dietrich",
        username: "Kamren",
        email: "Lucio_Hettinger@annie.ca",
        phone: "(254)954-1289",
        website: "demarco.info",
      },
    ];

    const columns = [
      { key: "name" },
      { key: "username" },
      { key: "email" },
      { key: "actions", width: 80 },
    ];
    const filter=""

    return {
      items,
      columns,
      filter
    };
  },
});
</script>

<style>
  .va-data-table__table-tr--expanded td {
    background: var(--va-background-border);
  }

  .va-data-table__table-expanded-content td {
    background-color: var(--va-background-element);
  }
</style>