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

Fix multi-row range selection on lazily paginated multi-selection Datatable (#7227) #7226

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

henrynguyen7
Copy link

@henrynguyen7 henrynguyen7 commented Feb 9, 2025

Attempts to fix #7227.

On a datatable that has the paginator enabled, with lazy=true, and selectionMode="multiple", then on the first page, shift-clicking multiple rows functions properly as expected by selecting all shift-clicked rows. However, when navigating to any page other than the first page, shift-clicking does NOT work, and instead cancels out any selection.

What's happening is that inside the selectRange() method of datatable, this.processedData contains an array of data that is rendered on the current page of the table, and we use the indexes of rows that the user has shift+clicked in order to access the array by those indexes, which we call rangeStart and rangeEnd. For example, consider a collection of data containing 50 total items. On a datatable displaying 10 rows at a time, this.processedData will contain an array of length 10, and when the user shift+clicks the first three rows, we will assign a rangeStart of 0 and a rangeEnd of 2 for selection.

The problem is that when we navigate to the other pages other than the first, this.processedData still only contains a subset of the total dataset, but our rangeStart and rangeEnd indexes contain the indexes relative to the entire total dataset. Continuing on with the previous example, when we navigate to page 2 and try to shift+click the first three rows, this.processedData still only contains an array of length 10, since we are only rendering 10 items at a time, but rangeStart will be 10 and rangeEnd will be 12, which are both outside the bounds of the this.processedData array so no rows end up being selected.

Currently there is code that is meant to account for this, by subtracting the number rows from previous pages so that we get the properly offset indexes relative to the this.processedData subset, not the total. Specifically, it first determines rangeStart and rangeEnd relative to the total dataset, and then subtracts this.first from both values, where this.first appears as though it's meant to be the number of items that are contained in the pages previous to the current page (a.k.a. the index of the first item on the current page of the subset of data from the total dataset).

The bug is that this.first does not actually contain the expected value here to properly perform the offset. Continuing from the above example, when shift+clicking the first three rows on the second page of results, rangeStart and rangeEnd will be 10 and 12 respectively, and we would expect that we subtract 10 from the first page of results to get correct values of 0 and 2. However, this.first is actually 0, and so we end up with rangeStart and rangeEnd of 10 and 12, which are outside the bounds of this.processedData which cannot be processed on subsequent lines.

This PR attempts to fix this bug by adjusting the subtraction to use this.d_first instead of this.first, which has been confirmed to contain the desired value of the total number of rows in previous pages. In the above example, it contains 10 for the second page, 20 for the third page, 30 for the fourth page, so on, which causes rangeStart and rangeEnd to contain the proper expected values for accessing this.processedData correctly.

Alternatively, we could've instead updated the assignment of this.first to contain this.d_first, so that the current code here would function correctly. However, I'm not sure what other undesired effects that might cause, so am requesting more knowledgeable eyes to review the above proposal. Many thanks!! 🙏 ❤️

###Defect Fixes
#7227

###Feature Requests
Due to company policy, we are unable to accept feature request PRs with significant changes as such cases has to be implemented by our team following our own processes.

…atable

On a datatable that has the paginator enabled, with lazy=true, and selectionMode="multiple", then on the first page, shift-clicking multiple rows functions properly as expected by selecting all shift-clicked rows. However, when navigating to any page other than the first page, shift-clicking does NOT work, and instead cancels out any selection.

What's happening is that inside the [`selectRange()`](https://github.com/primefaces/primevue/blob/master/packages/primevue/src/datatable/DataTable.vue#L1190) method of datatable, `this.processedData` contains an array of data that is rendered on the current page of the table, and we use the indexes of rows that the user has shift+clicked in order to access the array by those indexes, which we call [`rangeStart` and `rangeEnd`](https://github.com/primefaces/primevue/blob/master/packages/primevue/src/datatable/DataTable.vue#L1190). For example, consider a collection of data containing 50 total items. On a datatable displaying 10 rows at a time, `this.processedData` will contain an array of length 10, and when the user shift+clicks the first three rows, we will assign a `rangeStart` of 0 and a `rangeEnd` of 2 for selection.

The problem is that when we navigate to the other pages other than the first, `this.processedData` still only contains a subset of the total dataset, but our `rangeStart` and `rangeEnd` indexes contain the indexes relative to the entire total dataset. Continuing on with the previous example, when we navigate to page 2 and try to shift+click the first three rows, `this.processedData` still only contains an array of length 10, since we are only rendering 10 items at a time, but `rangeStart` will be 10 and `rangeEnd` will be 12, which are both outside the bounds of the `this.processedData` array so no rows end up being selected.

Currently there is [code that meant to account for this](https://github.com/primefaces/primevue/blob/master/packages/primevue/src/datatable/DataTable.vue#L1182C13-L1182C45), by subtracting the number rows from previous pages so that we get the properly offset indexes relative to the `this.processedData` subset, not the total. Specifically, it first determines `rangeStart` and `rangeEnd` relative to the total dataset, and then subtracts `this.first` from both values, where `this.first` appears as though it's meant to be the number of items that are contained in the pages previous to the current page (a.k.a. the index of the _first_ item on the _current_ page of the subset of data from the total dataset).

The bug is that `this.first` does not actually contain the expected value here to properly perform the offset. Continuing from the above example, when shift+clicking the first three rows on the second page of results, `rangeStart` and `rangeEnd` will be 10 and 12 respectively, and we would expect that we subtract 10 from the first page of results to get correct values of 0 and 2. However, `this.first` is actually 0, and so we end up with `rangeStart` and `rangeEnd` of 10 and 12, which are outside the bounds of `this.processedData` which cannot be processed on subsequent lines.

This PR attempts to fix this bug by adjusting the subtraction to use `this.d_first` instead of `this.first`, which has been confirmed to contain the desired value of the total number of rows in previous pages. In the above example, it contains 10 for the second page, 20 for the third page, 30 for the fourth page, so on, which causes `rangeStart` and `rangeEnd` to contain the proper expected values for accessing `this.processedData` correctly.

Alternatively, we could've instead updated the assignment of `this.first` to contain `this.d_first`, so that the current code here would function correctly. However, I'm not sure what other undesired effects that might cause, so am requesting more knowledgeable eyes to review the above proposal. Many thanks!! 🙏 ❤️
Copy link

vercel bot commented Feb 9, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Name Status Preview Updated (UTC)
primevue ⬜️ Ignored (Inspect) Visit Preview Feb 9, 2025 7:36am
primevue-v3 ⬜️ Ignored (Inspect) Visit Preview Feb 9, 2025 7:36am

@henrynguyen7 henrynguyen7 changed the title Fix multi-row range selection on lazily paginated multi-selection Datatable Fix multi-row range selection on lazily paginated multi-selection Datatable (#7727) Feb 9, 2025
@henrynguyen7 henrynguyen7 changed the title Fix multi-row range selection on lazily paginated multi-selection Datatable (#7727) Fix multi-row range selection on lazily paginated multi-selection Datatable (#7227) Feb 9, 2025
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.

Range selection is broken on non-first-pages for lazily-paginated multi-selection datatables
1 participant