Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 3, 2025

Problem

When using BTable/BTableLite with row-details, if the items array is replaced with new object references (even with the same data), the row-details would be hidden. This commonly happens in "Load more" scenarios where the entire items array is recreated with new objects.

Root Cause: The detailsMap used a WeakMap with object references as keys. When items were replaced with new objects, the WeakMap lost track of which rows had details open because the object references changed.

Solution

Updated BTableLite to use primary keys for tracking row-details state when the primary-key prop is provided:

  • Changed detailsMap from WeakMap<object> to Map<object | string> to support both primary key strings and object references
  • Modified generateDetailsItem to return the primary key string when primaryKey prop is provided and the item contains that key
  • Added getDetailsMapKey helper function for consistent map key generation throughout the component
  • Updated watcher logic to preserve existing details state when items are replaced with the same primary key value
  • Updated all template usages to use getDetailsMapKey(item) for map lookups
  • Falls back to object reference tracking when no primaryKey is provided (maintains full backward compatibility)

Usage

To enable row-details persistence across item updates, provide a primary-key prop:

<BTable :items="items" :fields="fields" primary-key="id">
  <template #cell(actions)="row">
    <BButton @click="row.toggleDetails">
      {{ row.detailsShowing ? 'Hide' : 'Show' }} Details
    </BButton>
  </template>
  <template #row-details="row">
    <BCard>Details for {{ row.item.name }}</BCard>
  </template>
</BTable>

When items are updated (e.g., in a "Load more" scenario):

// Items are replaced with new object references but same IDs
items.value = [
  { id: 1, name: 'Alice', age: 30 },  // New object but id: 1 remains
  { id: 2, name: 'Bob', age: 25 },    // New object but id: 2 remains
  { id: 3, name: 'Charlie', age: 35 } // New item added
]
// Row-details for items with id 1 and 2 will persist if they were open

Demo

The fix is demonstrated with two tables - one with primary-key and one without:

Comparison after Load More

  • Top table (with primary-key): Alice's details remain open after clicking "Load More" ✅
  • Bottom table (without primary-key): Alice's details are closed after clicking "Load More" (expected behavior for backward compatibility)

Changes

Core Implementation (BTableLite.vue):

  • detailsMap: WeakMap<object>Map<object | string> to support string keys
  • generateDetailsItem: Returns primary key string when primaryKey prop is provided
  • getDetailsMapKey: New helper function for consistent key generation
  • Template: Updated to use getDetailsMapKey(item) instead of direct item references
  • Watcher: Preserves toggled state across item replacements when primary keys match

Tests (table-lite.spec.ts):

  • Added test: "persists details when items are replaced with new object references but same primary key"
  • Added test: "falls back to object reference when primaryKey is not provided"
  • All existing tests continue to pass (1632 tests)

Backward Compatibility

✅ Fully backward compatible - when no primaryKey is provided, the component uses object references as before. This is a progressive enhancement that only activates when the primary-key prop is used.

Testing

  • ✅ All unit tests pass (1632 tests)
  • ✅ Linting passes
  • ✅ Build succeeds
  • ✅ Manual testing confirms fix works as expected

Fixes #[issue-number]

Original prompt

This section details on the original issue you should resolve

<issue_title>[BTable] row-details get hidden on "Load more"</issue_title>
<issue_description>### Describe the bug

Steps to reproduce (in the reproduction link)

  1. Click "Show details" to toggle row-details of a row
  2. Click "Load more", which adds one more item to the BTable items prop
  3. The row-details gets hidden - here I would expect that it remains open, because all the rows except the last one didn't change

Reproduction

https://stackblitz.com/edit/vue-bdwu1e7h?file=package.json%2Csrc%2Fcomponents%2FBTableTest.vue

Used Package Manager

yarn</issue_description>

<agent_instructions>In BTableLite, update the generate details to be either object | string, where the string is the object[primaryKey], doing this allows you to keep track of items by their primary key, avoiding issues with object references being disposed of. If no primary key is provided, or the item in props.items does not contain key of "primary key" (from the prop) it should default to using the object reference.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@VividLemon This is due to the way you're changing the reference of the object. In your displayed items, once you add a new dispalyed count, you are building new objects based on rawItems. Therefore, the new object isn't active, unlike the previous one.
let table = [];

      this.rawItems.forEach((item, index) => {
        let newItem = {
          isActive: item.isActive,
          age: item.age,
          name: item.name,
        };
        //adding a note on some items
        if (index % 2 === 0) {
          newItem['notes'] = 'test note';
        }
        table.push(newItem);
      });

Doing this is making new objects that you are displaying, therefore it is not a reference to the last object.

because all the rows except the last one didn't change

According to js, it did change, since its a different object reference. Changing to let newItem = item would work, because it is the same reference.

The implementation could possibly use an update that uses primary keys to keep track of similar items, and defaults to current behavior if not used. </comment_new>

Fixes #2870

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@bolt-new-by-stackblitz
Copy link

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@coderabbitai
Copy link

coderabbitai bot commented Oct 3, 2025

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands and usage tips.

…ems change

Co-authored-by: VividLemon <31498096+VividLemon@users.noreply.github.com>
Copilot AI changed the title [WIP] [BTable] row-details get hidden on "Load more" fix(BTableLite): Use primary key to persist row-details state when items change Oct 3, 2025
Copilot AI requested a review from VividLemon October 3, 2025 20:35
Copilot finished work on behalf of VividLemon October 3, 2025 20:35
@VividLemon
Copy link
Member

@xvaara @dwgray I'm not sure if this behavior is wanted. Originally when I implemented this functionality I thought it would be wanted to close details if you did something like switch pages in certain contexts. By adding primary key support here, this stuff would stay open in certain contexts. I'm just not sure the best UX if they should close again or not. The situation is if object references change.

@VividLemon
Copy link
Member

VividLemon commented Oct 9, 2025

When thinking about it, this is after all the intended purpose of the primary key. To persist data... But it leaves issues with the current implementation of WeakMap. I think it may need to dynamically choose between weakmap and map since strings don't fulfill the constraints of weakmap

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BTable] row-details get hidden on "Load more"

2 participants