'I need to update a Blazor page to update whenever the query string changes

I have a Blazor component named NavBar.razor that displays a Radzen navigation menu with a list of tags. When the user clicks a tag (RadzenPanelMenuItem), the component OrderBrowser.razor is loaded into the page next to the menu. The query string lets OrderBrowser.razor know what tag was selected. (See the OnInitializedAsync method below.) The component loads the associated orders into a grid.

This works fine the first time the user clicks a tag, but when they click a different tag, the OnInitializedAsync method does not execute, even though the uri changes. So I added an event handler to force a reload when the uri changes. This works, but, for some reason, it seems to reload twice, resulting in an undesirable blink when it reloads the 2nd time.

Does anyone know a better way to do this? Thanks.

Code from NavBar.razor:

@foreach (var item in TagsAndCounts)
{
    <Radzen.Blazor.RadzenPanelMenuItem 
        Text="@(item.Tag + " (" + item.Count + ")")"
        Path="@("orders/browse?tag=" + item.Tag)" />
}

Order grid from OrderBrowser.razor:

<OrderGrid Data="@orders" AllowPaging="false" />

Code from OrderBrowser.razor:

protected override async Task OnInitializedAsync()
{
    await base.OnInitializedAsync();

    NavManager.LocationChanged += NavManager_LocationChanged;

    var uri = NavManager.ToAbsoluteUri(NavManager.Uri);

    if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("tag", out var tag))
    {
        orders = await orderService.GetOrdersForTagAsync(tag);
    }
}

private void NavManager_LocationChanged(object sender, LocationChangedEventArgs e)
{
    NavManager.NavigateTo(NavManager.Uri, forceLoad: true);
}


Solution 1:[1]

Use this event

[Parameter]
[SupplyParameterFromQuery]
public string? Page { get; set; } = "0";

    protected override void OnParametersSet()
    {
     //Fire your Code her
    }

Solution 2:[2]

When you go from: yourUrl/tag/tagname1 and click to link yourUrl/tag/tagname2 it does not fire OnInitializedAsync, because new page was not created. It is intended and correct behavior. But bit confusing.

You can leverage new, with .net6 introduced, capability of SupplyFromQueryParameter attribute, which will change its value based on query string.

 [Parameter, SupplyParameterFromQuery(Name = "tag")] public string Tag { get; set; } = "";

Now you can do the magic inside seeter of the Tag property. Or, if you need to call async method inside setter (which is not a good practice), you can use OnParametersSet method. It is called right after parameters has been changed. So you also need a mechanism to check if tag parameter has been changed (because it is called every time *some* parameter has been changed )

bool tagUpdated = true;
string _tag ="";
[Parameter,SupplyParameterFromQuery] public string Tag { get => _tag; set { if (value != _tag) { _tag = value; tagUpdated = true; } } } 

protected override async Task OnParametersSetAsync()
{
if (tagUpdated)
    {
    tagUpdated = false;
    await YourAsyncCallAndOtherMagic();
    }
}

Note, that SupplyFromQueryParameter works only on pages (.razor components with @page directive)

(still not the most beautiful solution I guess. Open for suggestions...)

Solution 3:[3]

I found a solution. It's still a bit of a hack, but it seems to work. If anybody has any better solutions, please let me know. I just changed the event handler to get the new URL and update the page, instead of forcing a reload.

private async void NavManager_LocationChanged(object sender, LocationChangedEventArgs e)
{
    orders = await orderService.GetOrdersForTagAsync(tag);
    var index = NavManager.Uri.LastIndexOf("/");
    tag = NavManager.Uri.Substring(index + 1);
    if (tag != "open_orders")
    {
       StateHasChanged();
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Hashem Ahmed
Solution 2 Alamakanambra
Solution 3 Tim