Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table: Row selection is not cleaned up when table data is removed. #5850

Open
2 tasks done
niemyjski opened this issue Dec 28, 2024 · 4 comments
Open
2 tasks done

Table: Row selection is not cleaned up when table data is removed. #5850

niemyjski opened this issue Dec 28, 2024 · 4 comments

Comments

@niemyjski
Copy link

TanStack Table version

8.20.6

Framework/Library version

latest

Describe the bug and the steps to reproduce it

I'd expect some easy api's to remove selection by id and or some guidelines ho to maintain state when you know data is being removed. In my case I have web sockets that tell me data is being removed, and I want to ensure selection is in a good state (as I'm doing complex things like skipping refresh if there is a selection).

I modified the same here: https://tanstack.com/table/latest/docs/framework/react/examples/row-selection Just paste in this code, make a selection and then hit refresh data.

import { faker } from '@faker-js/faker';

export type Person = {
  id: number;
  firstName: string;
  lastName: string;
  age: number;
  visits: number;
  progress: number;
  status: 'relationship' | 'complicated' | 'single';
  subRows?: Person[];
};

const range = (len: number) => {
  const arr: number[] = [];
  for (let i = 0; i < len; i++) {
    arr.push(i);
  }
  return arr;
};

const newPerson = (): Person => {
  return {
    id: faker.number.int(40) + 1000,
    firstName: faker.person.firstName(),
    lastName: faker.person.lastName(),
    age: faker.number.int(40),
    visits: faker.number.int(1000),
    progress: faker.number.int(100),
    status: faker.helpers.shuffle<Person['status']>([
      'relationship',
      'complicated',
      'single',
    ])[0]!,
  };
};

export function makeData(...lens: number[]) {
  const makeDataLevel = (): Person[] => {
    return range(1).map((): Person => {
      return {
        ...newPerson(),
      };
    });
  };

  return makeDataLevel();
}

Your Minimal, Reproducible Example - (Sandbox Highly Recommended)

https://tanstack.com/table/latest/docs/framework/react/examples/row-selection

Screenshots or Videos (Optional)

No response

Do you intend to try to help solve this bug with your own PR?

None

Terms & Code of Conduct

  • I agree to follow this project's Code of Conduct
  • I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.
niemyjski added a commit to exceptionless/Exceptionless that referenced this issue Dec 28, 2024
@KevinVandy
Copy link
Member

We already have the table.resetRowSelection(true) API that you can call to clear row selection in an event. Or just call row.toggleSelected(false) to unselect the row being removed.

The reason we don't want the table to clear row selection of row ids that are no longer present in the table is that there are many reasons that rows will disappear from the table, but you'd still want them to stay selected. Manual server-side pagination being the most common. It would definitely upset a lot of people if every time a user paginated to a new page, the row selection state disappeared just because that particular row is not present in the data.

What kind of API do you propose besides row.toggleSelected(false) or table.setRowSelection, etc.?

niemyjski added a commit to exceptionless/Exceptionless that referenced this issue Dec 31, 2024
@niemyjski
Copy link
Author

Here is my current logic and I feel like it's very very verbose. I know what records were removed and so I just want to clear selection if they are there, and I want it to happen smartly (no redraw if not in selection). You already know the id function so passing id's or even objects makes sense to me.

 // Remove the event from the selection if it was selected
        if (table.getIsSomeRowsSelected()) {
            const { rowSelection } = table.getState();
            if (message.id && rowSelection[message.id]) {
                table.setRowSelection((old) => {
                    const filtered = Object.entries(old).filter(([id]) => id !== message.id);
                    return Object.fromEntries(filtered);
                });
            }
        }

What I basically want to do is just say table.removeRowSelection([id1, id2]) and or by single id (table.removeRowSelection(id1).

Also, side note: a huge portion of real-world apps are spa apps and I have no intention to ever use RCS. My backend is ASP.NET Core.

@KevinVandy
Copy link
Member

By "server-side", we're not talking about RSC or even SSR. We're just talking about 'manual' data transfermations like doing pagination, sorting, or filtering outside of the TanStack Table client-side logic. Like using the manualPagination option and then doing the pagination logic in the backend API logic. If I had to estimate, 80% of TanStack Table implementations are done that way.

As for a new API, I guess it could be helpful, but I don't see that much of a need for it. How about we add it to the v9 alpha branch where more APIs with a larger bundle size footprint are going to matter a lot less?

@niemyjski
Copy link
Author

niemyjski commented Dec 31, 2024

Thanks for the clarification. I am using manualPagination. I think the confusing part for me is as an api consumer is the following scenarios:

  1. If I have just one page of data then I'd assume I could use table.getRow(rowId) and then remove the row with an api (which I don't see). But with this approach It's unclear if row data or row selection is updated.
  2. If I have just one page of data then I have to find the selected rows using a ton of lines of code, remove the selection and mutate page data.
  3. If I have n pages, selection is across all pages and I need to clear it by id but I also must check for row data and slice that too.
  4. If I have n pages, I could be infinity scrolling and I'd also have to do # 3, but how does that mess with paging internally?

The more that I think about this, feels like having helpers to remove selection by id would be easiest like table.removeSelectionById similar to table.getRowModel().rowsById['row-id'] But, also maybe make it clear about removing table data too. Not sure how these could be combined due to 1-3. Possibly if you remove a row it could check the data and slice it via map lookup (id key, object instance the value) and remove selection? But I don't like people mutating the data and that kinda feels wrong.

niemyjski added a commit to exceptionless/Exceptionless that referenced this issue Dec 31, 2024
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

No branches or pull requests

2 participants