Sorting in Blazor WebAssembly is implemented similarly to any other application type. And by sorting, we mean ordering the data fetched from the backend by using some criterium. For example, the criterium is often a product name. It can also be something like the price, or we can combine both of those as a single criterium for ordering our products.
The sorting needs to be implemented both on the client-side (Blazor WebAssembly side) and the backend side – the Web API part.
For the complete navigation for this series, you can visit the Blazor Series page.
So, let’s get down to business.
Sorting Implementation in the Web API
To start things off, we are going to modify the ProductParameters
class by adding a new property:
public class ProductParameters { const int maxPageSize = 50; public int PageNumber { get; set; } = 1; private int _pageSize = 4; public int PageSize { get { return _pageSize; } set { _pageSize = (value > maxPageSize) ? maxPageSize : value; } } public string SearchTerm { get; set; } public string OrderBy { get; set; } = "name"; }
As you can see, we add only one property that will accept the query string parameter from the client-side and pass it to the server-side action. Additionally, we set the value for this property to the name as the default sorting value.
To continue, we are going to install the System.Linq.Dynamic.Core
library, to help us with the server-side sorting logic:
PM>Install-Package System.Linq.Dynamic.Core -Version 1.2.10
Now, let’s modify the RepositoryProductExtensions
class by adding a sorting logic:
public static IQueryable<Product> Sort(this IQueryable<Product> products, string orderByQueryString) { if (string.IsNullOrWhiteSpace(orderByQueryString)) return products.OrderBy(e => e.Name); var orderParams = orderByQueryString.Trim().Split(','); var propertyInfos = typeof(Product).GetProperties(BindingFlags.Public | BindingFlags.Instance); var orderQueryBuilder = new StringBuilder(); foreach (var param in orderParams) { if (string.IsNullOrWhiteSpace(param)) continue; var propertyFromQueryName = param.Split(" ")[0]; var objectProperty = propertyInfos.FirstOrDefault(pi => pi.Name.Equals(propertyFromQueryName, StringComparison.InvariantCultureIgnoreCase)); if (objectProperty == null) continue; var direction = param.EndsWith(" desc") ? "descending" : "ascending"; orderQueryBuilder.Append($"{objectProperty.Name} {direction}, "); } var orderQuery = orderQueryBuilder.ToString().TrimEnd(',', ' '); if (string.IsNullOrWhiteSpace(orderQuery)) return products.OrderBy(e => e.Name); return products.OrderBy(orderQuery); }
In this code, we dynamically create our orderQuery
by using Reflection and the StringBuilder
class and call the OrderBy
method from the Linq.Dynamic.Core
namespace, to execute that query.
For this logic to work, we have to include several namespaces:
using System.Linq; using System.Reflection; using System.Text; using System.Linq.Dynamic.Core;
Finishing Touches and Testing Web API’s Sorting Implementation
All we have left to do is to call this method in the ProductRepository
class:
public async Task<PagedList<Product>> GetProducts(ProductParameters productParameters) { var products = await _context.Products .Search(productParameters.SearchTerm) .Sort(productParameters.OrderBy) .ToListAsync(); return PagedList<Product> .ToPagedList(products, productParameters.PageNumber, productParameters.PageSize); }
Excellent.
Let’s test this:
And we have our correct result. We can see only four products because the paging returns only 4 items per page, and we can see they are sorted by the price in descending order.
Now, let’s continue with the implementation of Sorting in BlazorWebAssembly.
Sorting in Blazor WebAssembly Application
The first thing we are going to do is to create new Sort.razor
and .cs
files in the Components
folder:
Then, let’s add our select control in the razor file:
<section> <select class="form-control" @onchange="ApplySort"> <option value="-1">- Sort By -</option> <option value="name">Name</option> <option value="price">Price</option> <option value="price desc">Price DESC</option> </select> </section>
This is a simple drop-down list with a couple of options to use for sorting purposes. We can notice the @onChange
event that is going to trigger the ApplySort
method as soon as we choose any of our options.
After this, we have to modify the class file as well:
public partial class Sort { [Parameter] public EventCallback<string> OnSortChanged { get; set; } private async Task ApplySort(ChangeEventArgs eventArgs) { if (eventArgs.Value.ToString() == "-1") return; await OnSortChanged.InvokeAsync(eventArgs.Value.ToString()); } }
We have a single event callback parameter and the ApplySort
method with the ChangeEventArgs
parameter. As soon as we pick our sorting option, the ApplySort
method will trigger and if the value is different from -1, we call the OnSortChanged
event callback and execute the parent function with the sorting value.
That said, we have to modify the Products
page as well.
Let’s start with the razor file:
<div class="row"> <div class="col-md-5"> <Search OnSearchChanged="SearchChanged"/> </div> <div class="col-md-5"> <Sort OnSortChanged="SortChanged" /> </div> <div class="col-md-2"> <a href="/createProduct">Create Product</a> </div> </div> <div class="row"> <div class="col"> <ProductTable Products="ProductList" /> </div> </div> <div class="row"> <div class="col"> <Pagination MetaData="MetaData" Spread="2" SelectedPage="SelectedPage" /> </div> </div>
And continue with the class file, by adding a new method:
private async Task SortChanged(string orderBy) { Console.WriteLine(orderBy); _productParameters.OrderBy = orderBy; await GetProducts(); }
This method is going to be invoked from the Sort
component with the OnSortChanged
event callback and will accept the orderBy
parameter. Then, we just log that value (for a testing purpose), set the OrderBy
property of the _productParameters
object, and call the GetProducts
function to refresh the product list on the screen.
Applying a QueryString Parameter
Of course, we have to apply this orderBy
value to our HTTP request as a query string. To do that, we are going to modify the GetProducts
method in the ProductHttpRepository
class:
public async Task<PagingResponse<Product>> GetProducts(ProductParameters productParameters) { var queryStringParam = new Dictionary<string, string> { ["pageNumber"] = productParameters.PageNumber.ToString(), ["searchTerm"] = productParameters.SearchTerm == null ? "" : productParameters.SearchTerm, ["orderBy"] = productParameters.OrderBy }; //the rest of the code return pagingResponse; }
That’s all it takes.
Testing Our Application
Finally, we can start the server-side and the client-side applications, navigate to the Products page, and test all of the functionalities:
As we can see, everything is working without a problem.
Conclusion
Excellent.
We have learned how to implement Sorting in the Blazor WebAssembly application.
So, we are ready to continue with the Blazor WebAssembly Forms and Validation. And that’s exactly what we are going to learn about in the next article.