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

[data grid] combined usage of pagination and filter calls api twice with server-side data integration #15378

Closed
achoud444 opened this issue Nov 12, 2024 · 15 comments · Fixed by #16447
Assignees
Labels
breaking change component: data grid This is the name of the generic UI component, not the React module! enhancement This is not a bug, nor a new feature feature: Server integration Better integration with backends, e.g. data source v8.x

Comments

@achoud444
Copy link

achoud444 commented Nov 12, 2024

Steps to reproduce

Link to live example: (required)

Steps:
1.
2.
3.

Current behavior

I've implemented pagination and filtering, and everything works perfectly on page 1. However, when I navigate to page 2 or 3 and then apply a filter, it triggers the API call twice. Here’s a working example.

Additional questions:

  1. Is there any better way to use debounce?
  2. What is the tsx interface for apiRef?

Expected behavior

No response

Context

No response

Your environment

npx @mui/envinfo
  Don't forget to mention which browser you used.
  Output from `npx @mui/envinfo` goes here.

Search keywords: [Datagrid]: Pagniation and filter calls api twice

@achoud444 achoud444 added bug 🐛 Something doesn't work status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Nov 12, 2024
@michelengelen
Copy link
Member

@MBilalShafi another one for you ... Seems like updating with rows prop is sub-optimal here. Would be better to use the apiRef methods to update internal state ... WDYT?

@achoud444 regarding the API-interface: We do have documentation about that here.

@michelengelen michelengelen added component: data grid This is the name of the generic UI component, not the React module! feature: Server integration Better integration with backends, e.g. data source status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Nov 12, 2024
@michelengelen michelengelen changed the title [Datagrid]: Pagniation and filter calls api twice [data grid] combined usage of pagination and filter calls api twice with server-side data integration Nov 12, 2024
@MBilalShafi
Copy link
Member

MBilalShafi commented Nov 12, 2024

@achoud444 When using server-side pagination and (or) filtering the rowCount should be provided to the Data Grid for it to have proper information about the number of rows on the server.

In the mentioned example, since there's no rowCount provided, the Data Grid relies on the rows prop for extracting this information.

Now, when filtering on pages > 1, we have the useEffect running twice.

  1. Due to the update of filterModel
  2. Due to the update of paginationModel (when the rows count is reduced from the previous number the Data Grid adjusts the page number automatically, so it shifts to page 1, and another trigger of useEffect happens.)

I added a rowCount in the above example to remove this from happening: https://codesandbox.io/p/sandbox/sleepy-sunset-fy2gnm?file=%2Fsrc%2FDemo.tsx

But this is far from complete, the rowCount must reflect the up-to-date row count. For example, filtering may yield less rowCount than the previous one, so the updated number should be provided to the Data Grid.

Tip

If you are on a Pro or Premium plan, you might give the data source a try, which is an improved way to work with server-side data.

Let me know if you have further questions. Thanks

@achoud444
Copy link
Author

@MBilalShafi

In the mentioned example, since there's no rowCount provided, the Data Grid relies on the rows prop for extracting this information.

If you seem my exaple again. I have the rowCount with the updated information from the fetchUserData. Please have a look again.

I added a rowCount in the above example to remove this from happening: https://codesandbox.io/p/sandbox/sleepy-sunset-fy2gnm?file=%2Fsrc%2FDemo.tsx

You have added twice here

If you are on a Pro or Premium plan

Yes I have a Premium plan. But still can we do something here which prevents from calling it twice?

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Nov 12, 2024
@MBilalShafi
Copy link
Member

MBilalShafi commented Nov 12, 2024

Thanks @achoud444 for the clarification.

Yes, I overlooked that part with the rowCount already added, and adding a static rowCount suppressed the issue.
However, the reason for the issue would be the same, i.e. updation of the rowCount triggers a paginationModel change due to the following line being executed which causes the unnecessary useEffect call:

apiRef.current.setPage(Math.max(0, pageCount - 1));

I'll check and shortly update you with a possible solution.

@MBilalShafi
Copy link
Member

MBilalShafi commented Nov 13, 2024

@achoud444 I think it's the correct behavior.

Consider a scenario:

  • The user is on page 2 (6-10 results displayed)
  • The user applies a filter which triggers an API call to fetch the filtered rows.: { field: 'fullName', operator: 'equals', value: 'User 1' }
  • An empty response is received as there's no page: 2 on the server against the applied filter. { rows: [], rowCount: 1 }
  • Due to the update of rowCount the Data Grid updates the page 2 => 1 because page 2 doesn't exist against the current filter.
  • Another API call is sent to fetch page 1 due to the paginationModel update.

I visualized the API calls in the table below.

Call paginationModel filterModel Trigger
First { page: 1, pageSize: 5 } { items: [{ field: 'fullName', operator: 'equals', value: 'User 1' }] } User filters by "User 1"
Second { page: 0, pageSize: 5 } { items: [{ field: 'fullName', operator: 'equals', value: 'User 1' }] } Less rows than page 2, Grid shifts to page 1

Does it make sense or does your backend implementation work differently? If so, some details about its inputs/outputs would be helpful.

Or do you specifically want to skip the API call when rowCount gets equal to 0 because it doesn't make sense to fetch when there are no records?

@MBilalShafi MBilalShafi added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Nov 13, 2024
@achoud444
Copy link
Author

@MBilalShafi

Or do you specifically want to skip the API call when rowCount gets equal to 0 because it doesn't make sense to fetch when there are no records?

In my opinion, whenever the user is on a page other than page 1 and applies a filter, the API request should be made with the filter applied and the page set to 1 ?

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Nov 13, 2024
@michelengelen
Copy link
Member

@MBilalShafi

Or do you specifically want to skip the API call when rowCount gets equal to 0 because it doesn't make sense to fetch when there are no records?

... the page set to 1 ?

That's where the second call of useEffect will run. After the filterModel change (1. run), which results in a pagination change (2. run)

@MBilalShafi
Copy link
Member

In my opinion, whenever the user is on a page other than page 1 and applies a filter, the API request should be made with the filter applied and the page set to 1 ?

I think it's hard to reason about as a default behavior. What if filtering yields similar records? The page reset would be an unexpected behavior. Also, filtering doesn't necessarily yield page 1, it's basically the last page. (For example, if filtering yields 20 records, the last page would be 20/5 = 4)

The behavior could be tested with client-side filtering.

@achoud444
Copy link
Author

achoud444 commented Nov 13, 2024

@MBilalShafi

What if filtering yields similar records?

Even if the records are similar, the user would still need to search for the desired row within the page. For instance, if there are 20 records with a page size of 5, and the user is on page 2 when they apply a filter that yields 15 records, they would still need to locate their result. So, wouldn’t it be better to take them directly to page 1, allowing them to start their search from the beginning?

@MBilalShafi
Copy link
Member

MBilalShafi commented Nov 23, 2024

Wouldn’t it be better to take them directly to page 1, allowing them to start their search from the beginning?

👍 Although it seems an opinionated thing, it makes sense to me. Filtering usually gets followed up by locating the desired rows which makes more sense to be done from the beginning. However, there could be cases where the current behavior would make sense but I imagine those would be fewer.

For benchmark, I've done a quick comparison with a few other Table/Grid libraries and it seems both the patterns are being used.

Libraries that go to the last visible page on filtering.

  • MUI X Data Grid
  • AgGrid
  • Syncfusion Data Grid

Libraries that go to first page on filtering.

  • Kendo UI Data Grid
  • TanStack Table
  • Datatables.net table
  • Antd Table

I'd be in favor of changing this behavior as part of v8 breaking changes. Wdyt @mui/xgrid?

@MBilalShafi MBilalShafi removed the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Nov 23, 2024
@github-project-automation github-project-automation bot moved this to 🆕 Needs refinement in MUI X Data Grid Nov 23, 2024
@arminmeh
Copy link
Contributor

I have checked out other people experiences/expectations and I really liked this answer and its summary it all depends why the user is on any page other than the first one to begin with
I think that the majority of our users are actually falling into The case for, so we should change the default behavior (in v8)

@MBilalShafi
Copy link
Member

MBilalShafi commented Nov 25, 2024

Wdyt about making this a bit adaptable to support both the use cases, keeping in mind that The case against falls mostly around sorted data? So based on when a sort is applied:

  • Yes. Keep the current/last visible page (current behavior)
  • No. Move to page 1 (updated behavior)

Another option could be to make this behavior customizable by API (props.filteringResetsPagination: boolean) and keep the more relevant one the default. However, I'd not go for it until a significant need for both the use cases is there.

@arminmeh
Copy link
Contributor

arminmeh commented Nov 25, 2024

I think that even for sorting, resetting is covering more use cases.
Again, the question is why are you on the other page?
Are you looking specifically for a record with some average value so you want to sort and be already away from the start of the data set or you didn't find what you were looking for and thinking that by applying sorting your record will appear at the top of the list?

Another option could be to make this behavior customizable by API (props.filteringResetsPagination: boolean) and keep the more relevant one the default. However, I'd not go for it until a significant need for both the use cases is there.

Agree with this (let's leave it for later)

@cherniavskii
Copy link
Member

We discussed this today and made a decision to reset the page to 0 whenever the sorting model or filter model changes.
This applies to client-side sorting/filtering, server-side sorting/filtering, as well as the data source implementation (including lazy loading).
For v7, we want to port this behavior but keep it opt-in, so we don't introduce breaking changes.

Copy link

This issue has been closed. If you have a similar problem but not exactly the same, please open a new issue.
Now, if you have additional information related to this issue or things that could help future readers, feel free to leave a comment.

Note

@achoud444 How did we do? Your experience with our support team matters to us. If you have a moment, please share your thoughts in this short Support Satisfaction survey.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change component: data grid This is the name of the generic UI component, not the React module! enhancement This is not a bug, nor a new feature feature: Server integration Better integration with backends, e.g. data source v8.x
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants