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.
Parameters
Name | Type | Default | Required | Description | Added Version |
---|---|---|---|---|---|
DataProvider | AutoCompleteDataProviderDelegate<TItem> | null | ✔️ | Gets or sets the data provider. | 0.4.0 |
Disabled | bool | false | Gets or sets the disabled state. | 0.4.0 | |
EmptyText | string | No records found. | Gets or sets the empty text. | 1.10.2 | |
LoadingText | string | Loading... | Gets or sets the loading text. | 1.10.2 | |
Placeholder | string | null | Gets or sets the placeholder. | 0.4.0 | |
PropertyName | string | null | ✔️ | Gets or sets the property name. | 0.4.0 |
Size | AutoCompleteSize | AutoCompleteSize.Default | Gets or sets the autocomplete size. | 0.4.0 | |
StringComparison | StringComparison | StringComparison.OrdinalIgnoreCase | Gets or sets the StringComparison. | 0.4.1 | |
StringFilterOperator | StringFilterOperator | StringFilterOperator.Contains | Gets or sets the string filter operator. | 0.4.1 | |
Value | string | null | Gets or sets the value. | 0.4.0 | |
ValueExpression | expression | null | AutoComplete value expression. | 0.4.0 |
Methods
Name | Returns | Description | Added Version |
---|---|---|---|
Disable() | void | Disables autocomplete. | 0.4.0 |
Enable() | void | Enables autocomplete. | 0.4.0 |
RefreshDataAsync() | Task | Refresh the autocomplete data. | 0.4.0 |
ResetAsync() | Task | Resets the autocomplete selection. | 0.4.0 |
Events
Name | Description | Added Version |
---|---|---|
OnChanged | This event fires immediately when the autocomplete selection changes by the user. | 0.4.0 |
ValueChanged | This event fires on every user keystroke that changes the textbox value. | 0.4.0 |
Keyboard Navigation
Blazor Bootstrap autocomplete component supports the following keyboard shortcuts to initiate various actions.
Key | Description | Added Version |
---|---|---|
Esc | Closes the popup list when it is in an open state. | 1.3.1 |
Up arrow | Focuses on the previous item in the list. | 1.3.1 |
Down arrow | Focuses on the next item in the list. | 1.3.1 |
Home | Focuses on the first item in the list. | 1.3.1 |
End | Focuses on the last item in the list. | 1.3.1 |
Enter | Selects the currently focused item. | 1.3.1 |
Examples
Client side data
<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.");
}
}
public record Customer(int CustomerId, string CustomerName);
Client side data with StringComparision
In the below example, StringComparision.Ordinal
is used to make the filter case-sensitive.
info
By default, StringComparison.OrdinalIgnoreCase
is used to compare culture-agnostic and case-insensitive string matching.
<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.");
}
}
public record Customer(int CustomerId, string CustomerName);
Server side data
<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;
[Inject] ICustomerService _customerService { get; set; }
private async Task<AutoCompleteDataProviderResult<Customer>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer> request)
{
var customers = await _customerService.GetCustomers(request.Filter, request.CancellationToken); // API call
return await Task.FromResult(new AutoCompleteDataProviderResult<Customer> { Data = customers, TotalCount = customers.Count() });
}
private void OnAutoCompleteChanged(Customer customer)
{
// TODO: handle your own logic
// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
}
}
Set default value
<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
@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 for="supplier" class="col-md-2 col-form-label">Customer:</label>
<div class="col-md-10">
<AutoComplete @bind-Value="customerAddress.CustomerName"
TItem="Customer"
DataProvider="CustomersDataProvider"
PropertyName="CustomerName"
Placeholder="Search a customer..."
OnChanged="(Customer customer) => OnAutoCompleteChanged(customer)" />
<ValidationMessage For="@(() => customerAddress.CustomerName)" />
</div>
</div>
<div class="form-group row mb-3">
<label for="name" class="col-md-2 col-form-label">Address:</label>
<div class="col-md-10">
<InputText id="name" 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<Customer>> CustomersDataProvider(AutoCompleteDataProviderRequest<Customer> request)
{
var customers = await _customerService.GetCustomers(request.Filter); // API call
return await Task.FromResult(new AutoCompleteDataProviderResult<Customer> { Data = customers, TotalCount = customers.Count() });
}
private void OnAutoCompleteChanged(Customer customer)
{
// TODO: handle your own logic
// NOTE: do null check
Console.WriteLine($"'{customer?.CustomerName}' selected.");
Console.WriteLine($"Data null: {customer is null}.");
}
public class CustomerAddress
{
[Required]
public string CustomerName { get; set; }
[Required]
public string Address { get; set; }
}
}
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();
}