Search code examples
c#blazorblazor-server-side

How to pass the search string from the input field to the query parameters, when the binded blazor component property has changed?


How can I real-time update the request parameter in the URL when the user typing in the input text field?

Here is a simple sample of what I have:

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

<PageTitle>Home</PageTitle>
<h1>Search Persons</h1>
@* <search @bind="SearchString" @bind:event="oninput"/> *@
<input type="search" name="searchString" @bind="SearchString" @bind:event="oninput">
<QuickGrid TGridItem="Person" Items="FilteredPersons">
    <PropertyColumn Property="@(p => p.PersonId)" Sortable="true"/>
    <PropertyColumn Property="@(p => p.Name)" Sortable="true"/>
    <PropertyColumn Property="@(p => p.BirthDate)" Sortable="true"/>
</QuickGrid>

@code{
    [Parameter, SupplyParameterFromQuery] public string? SearchString { get; set; }

    private IQueryable<Person> FilteredPersons =>
        _persons.Where(m => m.Name.Contains(SearchString ?? string.Empty, StringComparison.InvariantCultureIgnoreCase));

    private record Person(int PersonId, string Name, DateOnly BirthDate);

    private readonly IQueryable<Person> _persons = new[]
    {
        new Person(10895, "Jean Martin", new DateOnly(1985, 3, 16)),
        new Person(10944, "António Langa", new DateOnly(1991, 12, 1)),
        new Person(11203, "Julie Smith", new DateOnly(1958, 10, 10)),
        new Person(11205, "Nur Sari", new DateOnly(1922, 4, 27)),
        new Person(11898, "Jose Hernandez", new DateOnly(2011, 5, 3)),
        new Person(12130, "Kenji Sato", new DateOnly(2004, 1, 9)),
    }.AsQueryable();

}

As you can see, nothing changes in the URL when the user enters a value into the filter. But in this case, it is expected to see https://localhost:44332/?search=J there.

Picture with app. Search string not passed into the qury parameters


Solution

  • The answer is simple. You just need to add a Callback after changing the parameter and apply the method NavigationManager.Navigate(string uri, bool forceLoad = false, bool replace = false). It is also recommended to use the bool replace = true parameter so as not to overload the browser page history with each new letter in the filter.

    NavigationManager.NavigateTo does not reload the page if only the request parameters are changed and the forceLoad = false.

    @page "/"
    @rendermode InteractiveServer
    @using Microsoft.AspNetCore.Components.QuickGrid
    @inject NavigationManager NavMan
    
    <PageTitle>Home</PageTitle>
    <h1>Search Persons</h1>
    <input type="search" name="searchString" @bind="SearchString" @bind:event="oninput" @bind:after="Callback">
    <QuickGrid TGridItem="Person" Items="FilteredPersons">
        <PropertyColumn Property="@(p => p.PersonId)" Sortable="true"/>
        <PropertyColumn Property="@(p => p.Name)" Sortable="true"/>
        <PropertyColumn Property="@(p => p.BirthDate)" Sortable="true"/>
    </QuickGrid>
    
    @code{
        [Parameter, SupplyParameterFromQuery] public string? SearchString { get; set; }
    
        private IQueryable<Person> FilteredPersons =>
            _persons.Where(m => m.Name.Contains(SearchString ?? string.Empty, StringComparison.InvariantCultureIgnoreCase));
    
        private record Person(int PersonId, string Name, DateOnly BirthDate);
    
        private readonly IQueryable<Person> _persons = new Person[]
        {
            /*Sample data*/
        }.AsQueryable();
    
        private void Callback()
        {
            var url = NavMan.GetUriWithQueryParameter(nameof(SearchString), SearchString);
            NavMan.NavigateTo(url);
        }
    }