Blazor - Add search box to simple data grid


Use case:  User want to be able to search the records for matching data.  The user does not want to have to learn complex query syntax or a coded language.  They want our search to work like Googles, you just type in words and it finds it for you.

Now that we have a usable data grid for our applications, [SimpleGrid], we will be adding a search box to it.  These are the steps we will need to take to add a search box to our application.

    1.       Add the UI   
    2.       Wire in the On click event
    3.       Allow the user to “clear” the search results

Before Search View



Search Box UI


There is nothing really special about our search box HTML:

    <div class="row searchactionrow">
        <div class="col-md-6">
            <div class="input-group">
                <input type="text" class="form-control" name="x" placeholder="Search term..." @bind="searchTerm" >
                <span class="input-group-btn">
                    <button class="btn btn-default" @onclick='Search' type="button"><span class="fas fa-search"></span> </button>
                    @if (filterOn)
                    {
                        <button type="button" class="btn btn-link" @onclick='ClearFilter'>Clear Filter</button>
                    }
                </span>
            </div>
        </div>
    </div>


We have an input box that is data bound to the variable, “searchTerm”.  We are using font awesome for the search magnifying glass icon.  We added a link button for the “clear” filter button so the user can clear out the search results and set the data grid back to all records.

The “searchactionrow” CSS just adjusts the padding around the search box.

Wire in the Search Onclick Event


This is where the cool part of Blazor shows off.  We create the method “Search” and wire in the actual search:

        protected void Search()

        {
            if (searchTerm.IsNotEmpty())
            {
                filterOn = false;
                var t = dataCollection
                .Where(x => x.Summary.ToLower().Contains(searchTerm))
                .Union(from c in dataCollection
                       .Where(x => (x.TemperatureC.ToString() ?? null).ToLower().Contains(searchTerm))
                       select c)
                .Union(from c in dataCollection
                       .Where(x => (x.TemperatureF.ToString() ?? String.Empty).ToLower().Contains(searchTerm))
                       select c)
                .Union(from c in dataCollection
                       .Where(x => (x.Date.ToLongDateString() ?? String.Empty).ToLower().Contains(searchTerm))
                       select c);
                if (t.Any())
                {
                    data = t.ToList();
                    filterOn = true;
                }
                searchTerm = "";
                this.StateHasChanged();
            }
        }

This is a fairly simple way to do a quick search of all the fields in a collection of objects.  If your collection is small, less than a million, this is a perforate solution.   We take the search term the user entered, then check each for a match.  We are looking for case insensitive matches, so we will ToLower the search term and the field values.  We need to make sure that we skip fields with null values, (x.Field ?? null).  For dates, we are going to use long date string, so if a user enters in “Dec” they will find matches.  It is noted that search by date ranges would need to be implemented differently.

We check if we found any matching records.  If so, we set them to the variable data, this is collection the gird display from.  We then clear out the search term and update the UI with a this.StateHasChange call.

After Search



You can see that our search worked, but the UI still shows 100 Records and the pagination.  We need to re-calculate those after the search, so we don’t confuse the user.


We make a change to the search method.  If we have results, we will need to do 2 things, re-calculate the paging and set the number of “Filter” records.  We can re-calculate the paging by call our grid service:

gridService.PageCount = gridService.GetPageCount(gridService.PageSize, t.ToList().Count);


Next, we need to add a new variable, filteredRecordCount and set it to the number of matching search records.  We will display this right above the total records count.

filteredRecordCount = t.ToList().Count;


Now let’s look at the new search results:





Nice and clean.  We did add a UI element to let the users know when there was no matches in the search.  It just show a message in red.

      <h4 class="noresults">@searchMessage</h4>     


Clear the Search Results



We need to add the ability for the user to “Clear out” the search result and get back to the full records set.  In the UI we added the Link button for this.

                    @if (filterOn)
                    {
                        <button type="button" class="btn btn-link" @onclick='ClearFilter'>Clear Filter</button>
                    }

Set the filter flag off, clear out the search term, set the UI data collection to the full collection and then update the UI.  And we are back to the full record set.


Bonus

While building the search box, I decided it would be cool to allow the user to simply hit the “Enter” key after entering in the search term.  I just needed to hook up a handler to the onkeyup event on the search term input element.  It needs to be noted that you have to use the “onkeyup” event so you can capture the special keys, such as backspace.


    private void RunLookup(KeyboardEventArgs e)
    {
        if (e.Key.Match("enter"))
        {
            Search();
            searchTerm = "";
        }
        else if(e.Key.Match("backspace"))
        {
            if (searchTerm.Length > 0)
            {
                searchTerm = searchTerm.Substring(0, searchTerm.Length - 1);
            }
        }
        else
        {
            searchTerm += e.Key;
        }
    }

On each key press, we are looking to see if enter was pressed.  If so, we execute the search.  If the user hit the backspace, we remove the last char of the search string if the string is not empty.  If it was not the enter or backspace key, we add the character to the search term string.

This was a cool feature to add to the simple grid that gives it a lot more power.  When I start building out my UI component library, future post, I will need to include my search box.


Comments

Popular posts from this blog

Yes, Blazor Server can scale!

Blazor new and improved Search Box

Blazor Wizard Step Component