Blazor Auto Complete
Blazor Bootstrap autocomplete component is a textbox that offers the users suggestions as they type from the data source. And it supports client-side and server-side filtering.
Client side data#
Example View Source
<div class="row">
<div class="col-md-5 col-sm-12">
<AutoComplete @bind-Value="customerName"
TItem="Customer"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
OnChanged="(Customer customer) => OnAutoCompleteChanged(customer)" />
</div>
</div>
@code {
private string customerName;
public IEnumerable<Customer> customers;
private async Task<AutoCompleteDataProviderResult<Customer>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer> request)
{
if (customers is null) // pull customers only one time for client-side autocomplete
customers = GetCustomers(); // call a service or an API to pull the customers
return await Task.FromResult(request.ApplyTo(customers.OrderBy(customer => customer.CustomerName)));
}
private IEnumerable<Customer> GetCustomers()
{
return new List<Customer> {
new(1, "Pich S"),
new(2, "sfh Sobi"),
new(3, "Jojo chan"),
new(4, "Jee ja"),
new(5, "Rose Canon"),
new(6, "Manju A"),
new(7, "Bandita PA"),
new(8, "Sagar Adil"),
new(9, "Isha Wang"),
new(10, "Daina JJ"),
new(11, "Komala Mug"),
new(12, "Dikshita BD"),
new(13, "Neha Gosar"),
new(14, "Preeti S"),
new(15, "Sagar Seth"),
new(16, "Vinayak MM"),
new(17, "Vijaya Lakhsmi"),
new(18, "Jahan K"),
new(19, "Joy B"),
new(20, "Zaraiah C"),
new(21, "Laura L"),
new(22, "Punith ES")
};
}
private void OnAutoCompleteChanged(Customer customer)
{
// TODO: handle your own logic
// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}
}
Client side data with StringComparision#
In the below example, StringComparision.Ordinal
is used to make the filter case-sensitive.
Example View Source
<div class="row">
<div class="col-md-5 col-sm-12">
<AutoComplete @bind-Value="customerName"
TItem="Customer"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
StringComparison="StringComparison.Ordinal"
OnChanged="(Customer customer) => OnAutoCompleteChanged(customer)" />
</div>
</div>
@code {
private string customerName;
public IEnumerable<Customer> customers;
private async Task<AutoCompleteDataProviderResult<Customer>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer> request)
{
if (customers is null) // pull customers only one time for client-side autocomplete
customers = GetCustomers(); // call a service or an API to pull the customers
return await Task.FromResult(request.ApplyTo(customers.OrderBy(customer => customer.CustomerName)));
}
private IEnumerable<Customer> GetCustomers()
{
return new List<Customer> {
new(1, "Pich S"),
new(2, "sfh Sobi"),
new(3, "Jojo chan"),
new(4, "Jee ja"),
new(5, "Rose Canon"),
new(6, "Manju A"),
new(7, "Bandita PA"),
new(8, "Sagar Adil"),
new(9, "Isha Wang"),
new(10, "Daina JJ"),
new(11, "Komala Mug"),
new(12, "Dikshita BD"),
new(13, "Neha Gosar"),
new(14, "Preeti S"),
new(15, "Sagar Seth"),
new(16, "Vinayak MM"),
new(17, "Vijaya Lakhsmi"),
new(18, "Jahan K"),
new(19, "Joy B"),
new(20, "Zaraiah C"),
new(21, "Laura L"),
new(22, "Punith ES")
};
}
private void OnAutoCompleteChanged(Customer customer)
{
// TODO: handle your own logic
// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}
}
NOTE
By default, StringComparison.OrdinalIgnoreCase
is used to compare culture-agnostic and case-insensitive string matching.
Server side data#
Example View Source
<div class="row">
<div class="col-md-5 col-sm-12">
<AutoComplete @bind-Value="customerName"
TItem="Customer2"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
OnChanged="(Customer2 customer) => OnAutoCompleteChanged(customer)" />
</div>
</div>
@code {
private string customerName;
[Inject] ICustomerService _customerService { get; set; }
private async Task<AutoCompleteDataProviderResult<Customer2>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer2> request)
{
var customers = await _customerService.GetCustomersAsync(request.Filter, request.CancellationToken); // API call
return await Task.FromResult(new AutoCompleteDataProviderResult<Customer2> { Data = customers, TotalCount = customers.Count() });
}
private void OnAutoCompleteChanged(Customer2 customer)
{
// TODO: handle your own logic
// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}
}
Set default value#
Example View Source
<div class="row">
<div class="col-md-5 col-sm-12">
<AutoComplete @bind-Value="customerName"
TItem="Customer"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
OnChanged="(Customer customer) => OnAutoCompleteChanged(customer)" />
</div>
</div>
@code {
private string customerName;
public IEnumerable<Customer> customers;
protected override void OnInitialized()
{
customerName = "Pich S";
}
private async Task<AutoCompleteDataProviderResult<Customer>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer> request)
{
if (customers is null) // pull customers only one time for client-side autocomplete
customers = GetCustomers(); // call a service or an API to pull the customers
return await Task.FromResult(request.ApplyTo(customers.OrderBy(customer => customer.CustomerName)));
}
private IEnumerable<Customer> GetCustomers()
{
return new List<Customer> {
new(1, "Pich S"),
new(2, "sfh Sobi"),
new(3, "Jojo chan"),
new(4, "Jee ja"),
new(5, "Rose Canon"),
new(6, "Manju A"),
new(7, "Bandita PA"),
new(8, "Sagar Adil"),
new(9, "Isha Wang"),
new(10, "Daina JJ"),
new(11, "Komala Mug"),
new(12, "Dikshita BD"),
new(13, "Neha Gosar"),
new(14, "Preeti S"),
new(15, "Sagar Seth"),
new(16, "Vinayak MM"),
new(17, "Vijaya Lakhsmi"),
new(18, "Jahan K"),
new(19, "Joy B"),
new(20, "Zaraiah C"),
new(21, "Laura L"),
new(22, "Punith ES")
};
}
private void OnAutoCompleteChanged(Customer customer)
{
// TODO: handle your own logic
// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}
}
Validations#
Example View Source
@using System.ComponentModel.DataAnnotations
<style>
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}
.invalid {
outline: 1px solid red;
}
.validation-message {
color: red;
}
</style>
<EditForm EditContext="@_editContext" OnValidSubmit="HandleOnValidSubmit">
<DataAnnotationsValidator />
<div class="form-group row mb-2">
<label class="col-md-2 col-form-label">Customer:</label>
<div class="col-md-10">
<AutoComplete @bind-Value="customerAddress.CustomerName"
TItem="Customer2"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
OnChanged="(Customer2 customer) => OnAutoCompleteChanged(customer)" />
<ValidationMessage For="@(() => customerAddress.CustomerName)" />
</div>
</div>
<div class="form-group row mb-3">
<label class="col-md-2 col-form-label">Address:</label>
<div class="col-md-10">
<InputText class="form-control" @bind-Value="customerAddress.Address" />
<ValidationMessage For="@(() => customerAddress.Address)" />
</div>
</div>
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-success float-right">Submit</button>
</div>
</div>
</EditForm>
@code {
private CustomerAddress customerAddress = new();
private EditContext _editContext;
[Inject] ICustomerService _customerService { get; set; }
protected override void OnInitialized()
{
_editContext = new EditContext(customerAddress);
base.OnInitialized();
}
public void HandleOnValidSubmit()
{
Console.WriteLine($"Customer name is {customerAddress.CustomerName} and address is {customerAddress.Address}");
}
private async Task<AutoCompleteDataProviderResult<Customer2>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer2> request)
{
var customers = await _customerService.GetCustomersAsync(request.Filter, request.CancellationToken); // API call
return await Task.FromResult(new AutoCompleteDataProviderResult<Customer2> { Data = customers, TotalCount = customers.Count() });
}
private void OnAutoCompleteChanged(Customer2 customer)
{
// TODO: handle your own logic
// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}
public class CustomerAddress
{
[Required]
public string CustomerName { get; set; }
[Required]
public string Address { get; set; }
}
}
Keyboard Navigation#
Blazor Bootstrap autocomplete component supports the following keyboard shortcuts to initiate various actions.
Key
Description
Esc
Closes the popup list when it is in an open state.
Up arrow
Focuses on the previous item in the list.
Down arrow
Focuses on the next item in the list.
Home
Focuses on the first item in the list.
End
Focuses on the last item in the list.
Enter
Selects the currently focused item.
Disable#
Use the Disabled
parameter to disable the AutoComplete
.
<div class="row mb-3">
<div class="col-md-5 col-sm-12">
<AutoComplete @bind-Value="customerName"
TItem="Customer2"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
Disabled="@disabled"
OnChanged="(Customer2 customer) => OnAutoCompleteChanged(customer)" />
</div>
</div>
<Button Color="ButtonColor.Primary" @onclick="Enable"> Enable </Button>
<Button Color="ButtonColor.Secondary" @onclick="Disable"> Disable </Button>
<Button Color="ButtonColor.Warning" @onclick="Toggle"> Toggle </Button>
@code {
private string customerName = default!;
private bool disabled = true;
[Inject] ICustomerService _customerService { get; set; } = default!;
private async Task<AutoCompleteDataProviderResult<Customer2>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer2> request)
{
var customers = await _customerService.GetCustomersAsync(request.Filter, request.CancellationToken); // API call
return await Task.FromResult(new AutoCompleteDataProviderResult<Customer2> { Data = customers, TotalCount = customers.Count() });
}
private void OnAutoCompleteChanged(Customer2 customer)
{
// TODO: handle your own logic
// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}
private void Enable() => disabled = false;
private void Disable() => disabled = true;
private void Toggle() => disabled = !disabled;
}
Also, use Enable() and Disable() methods to enable and disable the AutoComplete
.
NOTE
Do not use both the Disabled parameter and Enable() & Disable() methods.
<div class="row mb-3">
<div class="col-md-5 col-sm-12">
<AutoComplete @ref="autoComplete1"
@bind-Value="customerName"
TItem="Customer2"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
OnChanged="(Customer2 customer) => OnAutoCompleteChanged(customer)" />
</div>
</div>
<Button Color="ButtonColor.Secondary" @onclick="Disable"> Disable </Button>
<Button Color="ButtonColor.Primary" @onclick="Enable"> Enable </Button>
@code {
private AutoComplete<Customer2> autoComplete1 = default!;
private string customerName = default!;
[Inject] ICustomerService _customerService { get; set; } = default!;
private async Task<AutoCompleteDataProviderResult<Customer2>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer2> request)
{
var customers = await _customerService.GetCustomersAsync(request.Filter, request.CancellationToken); // API call
return await Task.FromResult(new AutoCompleteDataProviderResult<Customer2> { Data = customers, TotalCount = customers.Count() });
}
private void OnAutoCompleteChanged(Customer2 customer)
{
// TODO: handle your own logic
// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}
private void Disable() => autoComplete1.Disable();
private void Enable() => autoComplete1.Enable();
}