I have a mudblazor page that contains a table with tickets, it is possible to select these tickets and apply a filter based on a string entered in the searchbar. The selected tickets and the search string are saved in a session storage. The problem is that when I use the search function, the session storage for the selected tickets gets emptied.
I have figured out that it calls my updateSelection for storing the selected tickets in a session the same amount of times as the amount of rows currently loaded in. So if i have 25 rows, it will run updateSelecion() 25 times and setting an empty list.
This is the part of the table that would be calling the update functions:
<MudTable @ref="mudTableRef" Items="@TicketList" SelectedItemsChanged="@UpdateSelection" RowsPerPage="rowCount" RowsPerPageChanged="@UpdateRowCount" Filter="new Func<Ticket,bool>(FilterFunc1)" T="Ticket" OnRowClick="@RowClicked" SelectOnRowClick="false" Hover Bordered Striped MultiSelection>
<ToolBarContent>
<MudTextField @ref="mudSearchRef" Value="@searchString" ValueChanged="@(new EventCallback<string>(this, UpdateSearch))" Placeholder="Search" Variant="Variant.Outlined" Adornment="Adornment.End" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0" Clearable></MudTextField>
</ToolBarContent>
//headers, rows etc...
</MudTable>
These are the update functions:
private string searchString = "";
private HashSet<Ticket> selectedTickets = new HashSet<Ticket>();
async public void UpdateSearch(string searchStringField)
{
searchString = searchStringField;
// Save selected items to session storage
await sessionStorage.SetItemAsync("SessionSearch", searchString);
// Trigger a render to update the UI
StateHasChanged();
}
async public void UpdateSelection(HashSet<Ticket> selectedRows)
{
selectedTickets = selectedRows;
// Save selected items to session storage
await sessionStorage.SetItemAsync("SelectedTickets", selectedTickets);
// Trigger a render to update the UI
StateHasChanged();
}
This is the method I use for filtering the rows:
//Search for entered string in table data
private bool FilterFunc1(Ticket ticket) => FilterFunc(ticket, searchString);
private bool FilterFunc(Ticket ticket, string searchString)
{
if (string.IsNullOrWhiteSpace(searchString))
return true;
var selectedFilters = options.ToList();
// Define a dictionary to map field names to check functions
var fieldCheckFunctions = new Dictionary<string, Func<Ticket, string, bool>>
{
{ "Ticket Nr", (t, s) => $"{t.TicketId}".Contains(s) },
{ "Customer name", (t, s) => t.CustomerName.Contains(s, StringComparison.OrdinalIgnoreCase) },
{ "Main Category", (t, s) => t.MainCategory.Contains(s, StringComparison.OrdinalIgnoreCase) },
{ "Subcategory", (t, s) => t.Subcategory.Contains(s, StringComparison.OrdinalIgnoreCase) },
{ "Category type", (t, s) => t.CategoryType.Contains(s, StringComparison.OrdinalIgnoreCase) },
{ "Collection ticket Nr", (t, s) => t.CollectionTicketNr.Contains(s, StringComparison.OrdinalIgnoreCase) },
{ "Owner", (t, s) => t.Owner.Contains(s, StringComparison.OrdinalIgnoreCase) },
{ "Reported on", (t, s) => t.ReportedOn?.ToShortDateString().Contains(s, StringComparison.OrdinalIgnoreCase) == true },
{ "Due date", (t, s) => t.DueDate?.ToShortDateString().Contains(s, StringComparison.OrdinalIgnoreCase) == true }
};
// Check if the searchString matches any of the selected fields
foreach (var field in selectedFilters)
{
if (fieldCheckFunctions.TryGetValue(field, out var checkFunction) && checkFunction(ticket, searchString))
{
return true;
}
}
return false;
}
I have tried locking the update function when a search is called but it only works half of the time for some reason:
async public void UpdateSelection(HashSet<Ticket> selectedRows)
{
if (searchCalled)
{
searchCalledCount += 1;
if (searchCalledCount > TicketList.Count())
{
searchCalled = false;
searchCalledCount = 0;
}
}
else
{
searchCalled = false;
selectedTickets = selectedRows;
// Save selected items to session storage
await sessionStorage.SetItemAsync("SelectedTickets", selectedTickets);
// Trigger a render to update the UI
StateHasChanged();
}
}
async public void UpdateSearch(string searchStringField)
{
searchCalled = true;
searchString = searchStringField;
// Save selected items to session storage
await sessionStorage.SetItemAsync("SessionSearch", searchString);
// Trigger a render to update the UI
OnAfterRenderAsync(true);
StateHasChanged();
}
Also, this is how I get the values back from the session if that matters here because when searching you don't reload or leave the page:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
//Get table rowcount from session
rowCount = await sessionStorage.GetItemAsync<int?>("SessionRowCount") ?? 25;
//Get selected filters from session
options = await sessionStorage.GetItemAsync<HashSet<string>>("SessionOptions") ?? new HashSet<string>
{ "Ticket Nr", "Customer name", "Main Category", "Subcategory", "Category type", "Collection ticket Nr", "Owner", "Reported on", "Due date" };
mudSelectRef.SelectedValues = options;
//Get search string from session
searchString = (await sessionStorage.GetItemAsStringAsync("SessionSearch"))?.Trim('"') ?? string.Empty;
await mudSearchRef.SetText(searchString);
//Get Selected ticket from session
selectedTickets = await sessionStorage.GetItemAsync<HashSet<Ticket>>("SelectedTickets") ?? new HashSet<Ticket>();
// Bind selected items to the table instance
foreach (var ticket in selectedTickets)
{
var sessionTicket = mudTableRef.Items.SingleOrDefault(s => s.TicketId.Equals(ticket.TicketId));
if (sessionTicket is not null) mudTableRef.SelectedItems.Add(sessionTicket);
}
StateHasChanged();
}
}
Any help would be greatly appreciated!
I fixed it by making a copy of the current list before executing the search, i know this probably is not the best fix but I currently can't figure out how to do it any other way:
async public void UpdateSearch(string searchStringField)
{
// Create a copy of the current selectedTickets
HashSet<Ticket> selectedTicketsCopy = new HashSet<Ticket>(selectedTickets);
searchString = searchStringField;
// Save selected items to session storage
await sessionStorage.SetItemAsync("SessionSearch", searchString);
// Merge the copy and the current selectedTickets, removing duplicates
selectedTickets.UnionWith(selectedTicketsCopy);
UpdateSelection(selectedTickets);
}
async public void UpdateSelection(HashSet<Ticket> selectedRows)
{
selectedTickets = selectedRows;
// Save selected items to session storage
await sessionStorage.SetItemAsync("SelectedTickets", selectedTickets);
}