Skip to content

Document page index handling in QuickGrid#37020

Closed
guardrex wants to merge 2 commits into
mainfrom
guardrex-patch-3
Closed

Document page index handling in QuickGrid#37020
guardrex wants to merge 2 commits into
mainfrom
guardrex-patch-3

Conversation

@guardrex
Copy link
Copy Markdown
Collaborator

@guardrex guardrex commented Apr 16, 2026

Fixes #37019

Ilona ... A few years ago, a dev asked how to make the manually-built grid of an old Blazor Server EF Core sample return the user to the grid at the scroll position† where they left. [IIRC, QuickGrid had just come out at the time. The sample that we were discussing didn't use it. We don't even have that sample anymore.]

What I'd like to do in this area is cover page index management for QuickGrid. At the time, I was too busy to flesh out a page index example, but I reached it for work today. As usual, I want to provide a fully working, cut-'n-paste example. How does this look to you?

†BTW ... AFAIK, scroll position isn't something that can be tracked/set with a QuickGrid. I know that such a grid can be built that would do something like that, but I don't think that the built-in QuickGrid component has such a feature baked into it. If I'm wrong about that ... if there would be some way to preserve scroll position for coming back from a details page, please let me know. 👂


Internal previews

📄 File 🔗 Preview link
aspnetcore/blazor/components/quickgrid.md aspnetcore/blazor/components/quickgrid

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds documentation and a cut-and-paste sample showing how to preserve and restore a QuickGrid page index when navigating to a details page and back.

Changes:

  • Document PaginationState.CurrentPageIndex and PaginationState.SetCurrentPageIndexAsync for saving/restoring paging state.
  • Add Details.razor and Characters.razor example snippets using query string parameters to round-trip the page index.

Comment thread aspnetcore/blazor/components/quickgrid.md Outdated
Comment thread aspnetcore/blazor/components/quickgrid.md Outdated
Comment thread aspnetcore/blazor/components/quickgrid.md
Comment thread aspnetcore/blazor/components/quickgrid.md
Comment thread aspnetcore/blazor/components/quickgrid.md Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Luke Latham <1622880+guardrex@users.noreply.github.com>
@guardrex guardrex requested a review from ilonatommy April 16, 2026 23:46
@ilonatommy
Copy link
Copy Markdown
Member

†BTW ... AFAIK, scroll position isn't something that can be tracked/set with a QuickGrid.

Are you maybe able to find an issue with this ask? We have a quite big issue about scroll position dotnet/aspnetcore#26943 but the ask there is to set the position, not get it. I didn't treat it as a required/ask for feature when designing for scroll-to-index. In fact, such an API would be very costly. I would like more about where did this request originate from.

I have an impression that the sample is more about pagination than scroll position. If it's pagination, I believe dotnet/aspnetcore#65451 is adding pagination functionality that you need. We should edit the doc to use the approach from the PR.

cc @dariatiurina, I believe you could help Luke here.

@ilonatommy ilonatommy requested review from dariatiurina and removed request for ilonatommy May 13, 2026 10:48
@guardrex
Copy link
Copy Markdown
Collaborator Author

guardrex commented May 13, 2026

I have an impression that the sample is more about pagination than scroll position.

That's correct for this scenario, but let's discuss terminology in the docs first ...

For discussion just so that we're using the same terminology, the docs make careful, specific use of "SSR." In the docs, "SSR" merely means "server-side rendering" (as opposed to "CSR"/"client-side rendering," while "static SSR" means "static server-side rendering" and "interactive SSR" means "interactive server-side rendering." It's useful in the docs to make those distinctions and not use "SSR" to mean "static server rendering." Here are how the docs break down and use these terms for rendering concepts ...

It looks like your PR, @dariatiurina, is delivering QuickGrid features for static SSR in >=11.0 that normally work in <11.0 only for interactive SSR. This docs PR isn't assuming SSR at all ... either type. The approach on this docs PR should work with CSR as well.

I don't think that I have an issue for the original ask. The ask was from several years ago on I think an unrelated issue discussion with a dev about a custom grid that was being used in the EF Core-Blazor sample app, which we don't even maintain any longer. There was some overlap between that sample's manual grid approach and QuickGrid, but we never got around to putting a QuickGrid into that app. That app had a main page-detail page setup for EF Core examples. The user selects a record in the main page of paged results that opened a separate detail page (separate component). When the user was returned to the main page, the app did not return them to the correct page of filtered results.

The idea for this docs PR is just that it would be nice to show how to open a detail record in a new page (a different component) and then have a way to get back to the original QuickGrid page of paged (possibly filtered, too) results at the spot the user left. I think it can be done using CurrentPageIndex and SetCurrentPageIndexAsync as this PR shows, but I'd like to have one or both of you look at what's here and say if this is the right approach for this scenario. Again, this isn't about opening the detail on the same page that the QuickGrid is on. This is about opening the detail on a completely different page (different Razor component).

There's no rush on this. Wait until you get a few minutes to look, and we'll see if this is worth showing (I think it is) and if I created a decent 🦖 RexHacks!™ 🦖🙈😆 example using CurrentPageIndex/SetCurrentPageIndexAsync to get us started with discussing how to implement this type of setup. Indeed, what I did here might not be the best way to do something like this. Even if what I placed here isn't good to show, we're still lacking coverage on using CurrentPageIndex/SetCurrentPageIndexAsync for any scenario. Even if we don't use the example that I'm providing, we probably should place some kind of example relevant for the API and not merely just define the API. I went with this because it was a legitimate ask ... a common real-world problem that devs face all the time in CRUD-type apps.

Copy link
Copy Markdown

@dariatiurina dariatiurina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this work! I think that it would be better to have everything revolve around URL-based navigation without setting page manually in the state.

Comment thread aspnetcore/blazor/components/quickgrid.md
Comment thread aspnetcore/blazor/components/quickgrid.md
Comment thread aspnetcore/blazor/components/quickgrid.md
Comment thread aspnetcore/blazor/components/quickgrid.md
@dariatiurina
Copy link
Copy Markdown

And also note: this is an opt-out feature, so maybe there should be some note about feature flag?

@guardrex
Copy link
Copy Markdown
Collaborator Author

Thanks! Two things come to mind ...

  • This is looking like a bad use case example for both pieces of API. We'd be dropping SetCurrentPageIndexAsync, so we'd still need some kind of example for using that one. This use case (main page & detail page) still seems like a good thing to show developers, so we can place it under a different heading down near the bottom of the article.

  • WRT CurrentPageIndex and SetCurrentPageIndexAsync, we could decide to only mention this API in passing because the article already cross-links to the PaginationState class.

I'll work on this PR today and tomorrow and ping you back. I think we're headed in a great direction with it! 👍

@guardrex
Copy link
Copy Markdown
Collaborator Author

guardrex commented May 13, 2026

@dariatiurina ... Neither of your suggestions seems to work here. Adding +1 results in the wrong page of QG results loading, and not calling SetCurrentPageIndexAsync results in the index (0) of results always loading. Also, my code example seems to work fine under static SSR.

For reference in case you want to drop them into a test app, here are the 🦖 RexHacks!™ 🦖🙈😆 components that I've had luck with ...

Characters.razor:

@page "/characters"
@rendermode InteractiveServer
@using Microsoft.AspNetCore.Components.QuickGrid

<QuickGrid Items="character" Pagination="pagination">
    <PropertyColumn Property="@(c => c.Id)" />
    <PropertyColumn Property="@(c => c.Name)" />
    <TemplateColumn Context="c">
        <a href="@($"/details?id={c.Id}&page={pagination.CurrentPageIndex}")">
            Details
        </a>
    </TemplateColumn>
</QuickGrid>

<Paginator State="pagination" />

@code {
    PaginationState pagination = new PaginationState { ItemsPerPage = 3 };

    private record Character(int Id, string Name);

    private IQueryable<Character> character = new[]
    {
        new Character(0, "Ellen Ripley"),
        new Character(1, "Darth Vader"),
        new Character(2, "Rick Deckard"),
        new Character(3, "Sarah Connor"),
        new Character(4, "Malcolm Reynolds"),
        new Character(5, "Kara Thrace"),
        new Character(6, "James Kirk"),
        new Character(7, "Flash Gordon"),
        new Character(8, "Max Rockatansky"),
        new Character(9, "Katniss Everdeen"),
        new Character(10, "Ellie Sattler"),
        new Character(11, "Leela")
    }.AsQueryable();

    [SupplyParameterFromQuery]
    private int Page { get; set; }

    protected override async Task OnInitializedAsync()
    {
        await pagination.SetCurrentPageIndexAsync(Page);
    }
}

Details.razor:

@page "/details"

<ul>
    <li>Character ID for this detail record: @Id</li>
    <li>QuickGrid page index: @Page</li>
</ul>
<div>
    <a href="@($"/characters?page={Page}")">Back to List</a>
</div>

@code {
    [SupplyParameterFromQuery]
    private int Id { get; set; }

    [SupplyParameterFromQuery]
    private int Page { get; set; }
}

Can you give me your versions of the pair of components that you would recommend so that I can see what you're suggesting in action here?

@dariatiurina
Copy link
Copy Markdown

@guardrex Hi! I don't understand what exactly isn't working for you, because these two components work perfectly fine for me 😥. But I tested them on main in aspnetcore repo in BlazorUnitedApp, so maybe we have different builds and setups?

Characters.razor:

@page "/characters"
@using Microsoft.AspNetCore.Components.QuickGrid

<QuickGrid Items="character" Pagination="pagination">
    <PropertyColumn Property="@(c => c.Id)" />
    <PropertyColumn Property="@(c => c.Name)" />
    <TemplateColumn Context="c">
        <a href="@($"/details?id={c.Id}&page={pagination.CurrentPageIndex+1}")">
            Details
        </a>
    </TemplateColumn>
</QuickGrid>

<Paginator State="pagination" />

@code {
    PaginationState pagination = new PaginationState { ItemsPerPage = 3 };

    private record Character(int Id, string Name);

    private IQueryable<Character> character = new[]
    {
        new Character(0, "Ellen Ripley"),
        new Character(1, "Darth Vader"),
        new Character(2, "Rick Deckard"),
        new Character(3, "Sarah Connor"),
        new Character(4, "Malcolm Reynolds"),
        new Character(5, "Kara Thrace"),
        new Character(6, "James Kirk"),
        new Character(7, "Flash Gordon"),
        new Character(8, "Max Rockatansky"),
        new Character(9, "Katniss Everdeen"),
        new Character(10, "Ellie Sattler"),
        new Character(11, "Leela")
    }.AsQueryable();

    [SupplyParameterFromQuery]
    private int Page { get; set; }
}

Details.razor

@page "/details"

<ul>
    <li>Character ID for this detail record: @Id</li>
    <li>QuickGrid page index: @Page</li>
</ul>
<div>
    <a href="@($"/characters?page={Page}")">Back to List</a>
</div>

@code {
    [SupplyParameterFromQuery]
    private int Id { get; set; }

    [SupplyParameterFromQuery]
    private int Page { get; set; }
}

@guardrex
Copy link
Copy Markdown
Collaborator Author

guardrex commented May 14, 2026

Here's what happens when ...

protected override async Task OnInitializedAsync()
{
    await pagination.SetCurrentPageIndexAsync(Page);
}

... isn't present ...

movie1.mp4

It always loads the Characters component back at the first page of records (Index: 0).

Here's what happens when ...

pagination.CurrentPageIndex + 1

... +1 is added ...

movie2.mp4

It always loads the Characters component one page too far in advance of the paged results where the record was originally selected.

The only way the Back to List link works here is if both the OnInitializedAsync piece is there and the ?page/Page param is just pagination.CurrentPageIndex.

Mmmmm ... we can't publish content on this until we agree what works and why each of us can't get the other's approach to work on our respective systems/SDKs. Should we wait until @ilonatommy returns next week to break the tie?! LOL 😆

My setup is ...

  • SDK: 10.0.300
  • BWA target: 10.0
  • Microsoft.AspNetCore.Components.QuickGrid: 10.0.8

@guardrex
Copy link
Copy Markdown
Collaborator Author

One clarification tho ...

And also note: this is an opt-out feature, so maybe there should be some note about feature flag?

What does "this" refer to? ... and can you give me the code snippet to opt-out of it?

@dariatiurina
Copy link
Copy Markdown

@guardrex Okay, I can see the problem 😊. When you click on the next page in your example, URL doesn't change. Here how it's supposed to look like. I tested it with my components.

quickgrid.mp4

This is a part of a new URL-based navigation. It's enables by default and you can disable it like this:

AppContext.SetSwitch("Microsoft.AspNetCore.Components.QuickGrid.EnableUrlBasedQuickGridNavigationAndSorting", false);

@guardrex
Copy link
Copy Markdown
Collaborator Author

Ah! I see! 😮 ... and WRT "new," you mean new in 11.0?

Two things ...

  • General feature coverage for the new URL-based navigation. May I have the PU issue and PU PR for the new navigation? I'll get it scheduled for coverage.
  • I don't think that there will be any other examples that require work for the new URL-based navigation because we only lightly cover PaginationState. IIRC, what we're discussing on this PR is the first time that we've looked to cover details on paged results and the main page-detail page use case.

I'll update this PR this afternoon and ping you back. Thanks for solving the mystery here! 🕵️‍♀️😆

@dariatiurina
Copy link
Copy Markdown

Yep, it's for 11. Here is PR: dotnet/aspnetcore#65451 and here is issue: dotnet/aspnetcore#51249

You're welcome (^____^)

@guardrex
Copy link
Copy Markdown
Collaborator Author

Closing in favor of #37154.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add example of a details page that returns to the viewed page of a paged QG component

4 participants