2
\$\begingroup\$

Here is the working fiddle: https://blazorfiddle.com/s/d04xl2zi

I started a new project where they are using .net 8 blazor server interactivity. (I'm a bit new to blazor) they were interested in a select (dropdown) but one that allows type ahead (searching). I created a reusable component.

I created a reusable component called SelectWithAutoComplete. It accepts a list and accepts a callback function for onselected. I was hoping for a code review to tell me if I'm missing any functionality or if something could be improved.

@typeparam TItem

<div class="dropdown position-relative" @onfocusout="HandleFocusOut" style="max-width: 100%;">
    <input type="text"
           @bind="searchText"
           @bind:event="oninput"
           @onfocus="()=> dropdownOpen = true"
           placeholder="@Placeholder"
           class="form-control"
           style="cursor: pointer; padding-right: 2.5rem; max-width: 100%;" />

    <!-- Clear button -->
    @if (!string.IsNullOrWhiteSpace(searchText) || SelectedItem != null)
    {
        <span style="
                position: absolute;
                top: 50%;
                right: 2rem;
                transform: translateY(-50%);
                cursor: pointer;
                color: gray;
            "
            @onclick="ClearSelection">
            ✖
        </span>
    }

    <!-- Dropdown arrow -->
    <span style="
            position: absolute;
            top: 50%;
            right: 0.5rem;
            transform: translateY(-50%);
            cursor: pointer;
            color: gray;
        "
        @onclick="ToggleDropdown">
        ▼
    </span>

    @if (dropdownOpen && GetFilteredItems().Any())
    {
        <ul class="dropdown-menu show w-100 mt-0" style="max-height: 200px; overflow-y: auto;">
            @foreach (var item in GetFilteredItems())
            {
                <li>
                    <button type="button" class="dropdown-item" @onmousedown="() => SelectItem(item)">
                        @ItemText(item)
                    </button>
                </li>
            }
        </ul>
    }
</div>



@code {
    [Parameter] public List<TItem> Items { get; set; } = new();
    [Parameter] public Func<TItem, string> ItemText { get; set; }
    [Parameter] public string Placeholder { get; set; } = "Select or type...";
    [Parameter] public EventCallback<TItem> SelectedItemChanged { get; set; }
    [Parameter] public TItem SelectedItem { get; set; }

    private string searchText = string.Empty;
    private bool dropdownOpen = false;

  private List<TItem> GetFilteredItems() =>
    string.IsNullOrWhiteSpace(searchText)
        ? Items
        : Items.Where(x => ItemText(x).Contains(searchText, StringComparison.InvariantCultureIgnoreCase))
               .ToList();

   private async Task SelectItem(TItem item)
    {
        SelectedItem = item;
        searchText = ItemText(item);
        dropdownOpen = false;
        await SelectedItemChanged.InvokeAsync(item);
    }

      private async void HandleFocusOut(FocusEventArgs e)
    {
        dropdownOpen = false;

        var match = Items.FirstOrDefault(x => string.Equals(ItemText(x), searchText, StringComparison.InvariantCultureIgnoreCase));

        if (match != null)
        {
            SelectedItem = match;
            searchText = ItemText(match);
            await SelectedItemChanged.InvokeAsync(match);
        }
        else
        {
            SelectedItem = default;
            searchText = string.Empty;
            await SelectedItemChanged.InvokeAsync(default);
        }
    }
    private async void ClearSelection()
    {
        SelectedItem = default;
        searchText = string.Empty;
        dropdownOpen = false;
        await SelectedItemChanged.InvokeAsync(default);
    }

    private void ToggleDropdown()
    {
        if (!dropdownOpen)
        {
            searchText = string.Empty;
        }

        dropdownOpen = !dropdownOpen;
    }
}
\$\endgroup\$

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.