In this module we are going to add a Category Filter feature and finally wire up those Category buttons on the left side of the UI.
Modify the View Model
The first thing we are going to do is modify the View Model. Whenever we select a new category we are going to need to keep track of what the current category is during paging and sorting. So, we are going to add a CurrentCategory
property to the VehiclesListViewModel
class.
Modify the VehiclesListViewModel class with the code shown below.
FredsCars\Models\ViewModels\VehiclesListViewModel.cs
namespace FredsCars.Models.ViewModels
{
public class VehiclesListViewModel
{
public List<Vehicle> Vehicles { get; set; } = new();
public PagingInfo PagingInfo { get; set; } = new();
public SortingInfo SortingInfo { get; set; } = new();
public string? CurrentCategory { get; set; }
}
}
Update the Home Controller
Now we need to update the Home Controller to filter the Vehicle results based on a category and set the new CurrentCategory
property in the View Model to a value for tracking across paging and sorting.
Modify the Home controller with the code shown below.
FredsCars\Controllers\HomeController.cs
... existing code ...
namespace FredsCars.Controllers
{
public class HomeController : Controller
{
private IVehicleRepository _repo;
public int PageSize = 5;
//public int PageSize = 3;
public HomeController(IVehicleRepository repo)
{
_repo = repo;
}
public async Task<ViewResult> Index(
string? category,
int pageNumber = 1,
string sortColumn = "make",
string sortOrder = "asc")
{
var vehicles = _repo.Vehicles;
// Category fitler
vehicles = vehicles.Where(v =>
category == null || v.VehicleType.Name == category);
#region Sorting
... existing code ...
#endregion Sorting
return View(new VehiclesListViewModel
{
Vehicles = await vehicles
.AsNoTracking()
.Skip((pageNumber - 1) * PageSize)
.Take(PageSize)
.Include(v => v.VehicleType)
.ToListAsync(),
PagingInfo = new PagingInfo
{
PageIndex = pageNumber,
PageSize = this.PageSize,
TotalItemCount = _repo.Vehicles.Count()
},
SortingInfo = new SortingInfo
{
CurrentSortColumn = sortColumn.ToUpper(),
CurrentSortOrder = sortOrder.ToUpper()
},
CurrentCategory = category
});
}
}
}
In the code above, we modified the Index method of the Home controller to take in a new parameter named category of type nullable string.
Next we modify the vehicles IQueryable to filter by category based on the new parameter value.
vehicles = vehicles.Where(v =>
category == null || v.VehicleType.Name == category);
In the above statement, we have an OR (||
) condition. If the category is null, then for each vehicle the condition is true so all vehicles will be included in the results of the IQueryable. (In this case the right side of the OR condition will be ignored or, short circuited.) OR, if category == null
is not true only the vehicles whose VehicleType’s Name property is equal to the incoming category parameter’s value will be included in the results.
Notice, we do the filtering first before sorting or paging. We need to filter out the vehicles we want, than sort those results, and then get the current page, in that order.
And finally, we set the new CurrentCategory property of the view model to the value of the incoming category parameter.
CurrentCategory = category
Fix the Current Unit Tests
Because we have added a new parameter to the beginning of the parameter list in the Index method of the Home controller, all of our Home controller unit tests are currently failing.

We need to modify all of our Act statements in the unit tests where we call the Index method of the Home controller with the mocked repo.
Make the following modifications for the Act statement in each unit test.
Can_Access_VehicleList_FromVehicleRepo
VehiclesListViewModel? result =
(await controller.Index(null)).ViewData.Model
as VehiclesListViewModel;
Can_Page_Results
// Act
VehiclesListViewModel? result =
(await controller.Index(null, 2)).ViewData.Model
as VehiclesListViewModel;
Can_Return_PagingInfo
VehiclesListViewModel? result =
(await controller.Index(null, 2)).ViewData.Model
as VehiclesListViewModel;
Can_Sort_ByModel_Asc
VehiclesListViewModel? result =
(await controller.Index(null, 1, "model", "asc"))
.ViewData.Model as VehiclesListViewModel;
Can_Sort_ByModel_Desc
VehiclesListViewModel? result =
(await controller.Index(null, 1, "model", "desc"))
.ViewData.Model as VehiclesListViewModel;
Now if you do a test run on all of the tests they should all succeed.
Unit Test the Category Filter
Now that we have updated all of our current test we can go ahead and unit test the category filtering feature.