Reputation: 1
I'm working on a Blazor Web App that interacts with my SQL Server, and I'm trying to create a reusable custom Razor component for a virtualized FluentCombobox.
The goal is to pass in a list of objects of any type, along with functions to extract the display text and return value for each item.
Here's the definition of my first example object, ParameterValue
:
// ID of the parameter value
public int? ID { get; set; }
// display text to show in comboboxes
public string ParameterText { get; set; }
Since I have a large number of items, rendering all of them right away led to some significant wait times, so I decided to add the virtualization. Additionally, I want users to be able to search/filter items by typing into the combobox. For this, I’m currently using an autocomplete approach. This worked fine before, but adding the virtualization introduced a couple of problems with the search.
Issues I'm facing:
Selected ID displayed instead of text: when I select an item, the combobox shows the ID instead of the display text.
Search behavior: Searching works for values currently displayed, but entering a character that isn't part of the current list empties the combobox.
Search lag: the search input seems to be one character behind.
For example:
a
→ args = ""ab
→ args = "a"b
→ args = "ab"Here's my current implementation for the Razor component:
@typeparam TOption
<FluentCombobox TOption="string" Placeholder="@Placeholder" Autocomplete="@Autocomplete" Height="@Height"
@oninput="OnInputChanged"
@onchange="OnItemSelected">
@if (FilteredItems != null && FilteredItems.Count > 0)
{
<Virtualize Context="item" ItemsProvider="LoadItems" ItemSize="50" OverscanCount="5">
<FluentOption Value="@GetItemValue(item)">
@GetItemText(item)
</FluentOption>
</Virtualize>
}
else
{
<div>Loading...</div>
}
</FluentCombobox>
@code {
[Parameter] public List<TOption> Items { get; set; } = new List<TOption>();
[Parameter] public string Placeholder { get; set; } = "Make a selection...";
[Parameter] public ComboboxAutocomplete Autocomplete { get; set; } = ComboboxAutocomplete.Both;
[Parameter] public string Height { get; set; } = "200px";
[Parameter] public Func<TOption, string>? ItemTextSelector { get; set; }
[Parameter] public Func<TOption, string>? ItemValueSelector { get; set; }
[Parameter] public EventCallback<string> ValueChangedCallback { get; set; }
[Parameter] public string ReturnFieldName { get; set; }
private string? SelectedId { get; set; }
private List<TOption> FilteredItems { get; set; } = new List<TOption>();
protected override void OnInitialized()
{
FilteredItems = Items;
}
private async ValueTask<ItemsProviderResult<TOption>> LoadItems(ItemsProviderRequest request)
{
var totalItemCount = FilteredItems.Count;
var requestedItems = FilteredItems.Skip(request.StartIndex).Take(request.Count).ToList();
return new ItemsProviderResult<TOption>(requestedItems, totalItemCount);
}
private void OnInputChanged(ChangeEventArgs e)
{
var searchTerm = ((string)e.Value)?.ToString();
if (!string.IsNullOrEmpty(searchTerm))
{
FilteredItems = Items
.Where(i => GetItemText(i).Contains(searchTerm, StringComparison.OrdinalIgnoreCase))
.ToList();
}
else
{
FilteredItems = new List<TOption>(Items);
}
StateHasChanged();
}
private void OnItemSelected(ChangeEventArgs e)
{
var selectedValue = e.Value?.ToString();
TOption selectedItem = Items.FirstOrDefault(i => GetItemValue(i) == selectedValue);
if (selectedItem != null)
{
ValueChangedCallback.InvokeAsync(GetPropertyValue(selectedItem, ReturnFieldName));
}
StateHasChanged();
}
private string GetPropertyValue(TOption item, string propertyName)
{
var propertyInfo = typeof(TOption).GetProperty(propertyName);
return propertyInfo?.GetValue(item)?.ToString() ?? string.Empty;
}
private string GetItemText(TOption item)
{
return ItemTextSelector != null ? ItemTextSelector(item) : item?.ToString();
}
private string GetItemValue(TOption item)
{
return ItemValueSelector != null ? ItemValueSelector(item) : item?.ToString();
}
}
I've tried debugging the input lag but couldn't figure out why it's one character behind. From what I found online, it seems to be an issue related to how Blazor updates the DOM vs. when the event is processed.
For the display issue, I suspect it might have something to do with how I'm binding the selected value.
Questions:
How can I ensure that the display text is shown in the combobox after selecting an item instead of its ID?
Why does my search input lag behind by one character, and how can I fix this?
Is there a better way to handle virtualization in combination with search filtering in this scenario?
I'm quite new to Blazor and web development in general, so any advice or suggestions would be greatly appreciated!
If there's a better approach entirely or if you can point me toward useful resources, that would be very helpful as well.
Best regards
RA7
Upvotes: 0
Views: 214