|
| 1 | +--- |
| 2 | +title: How to Automatically Select Preselected Item on Blur |
| 3 | +description: Learn how to configure the Telerik ComboBox for Blazor to automatically select the first matching item when the input loses focus. |
| 4 | +type: how-to |
| 5 | +page_title: How to Automatically Select Preselected Item on Blur |
| 6 | +slug: combobox-kb-autoselect-on-blur |
| 7 | +tags: telerik, blazor, combobox, blur, auto-select |
| 8 | +res_type: kb |
| 9 | +--- |
| 10 | + |
| 11 | +## Environment |
| 12 | + |
| 13 | +<table> |
| 14 | + <tbody> |
| 15 | + <tr> |
| 16 | + <td>Product</td> |
| 17 | + <td>ComboBox for Blazor</td> |
| 18 | + </tr> |
| 19 | + </tbody> |
| 20 | +</table> |
| 21 | + |
| 22 | +## Description |
| 23 | + |
| 24 | +The article asnwers to the following question: |
| 25 | + |
| 26 | +* How to configure the ComboBox to automatically select the first matching item when the input loses focus (e.g., when the user tabs away or clicks outside)? |
| 27 | +* How to auto-select a ComboBox item based on user input when focus is lost? |
| 28 | +* Can the ComboBox select a suggested item on blur without pressing Enter? |
| 29 | +* How to set the ComboBox value when the user leaves the input field? |
| 30 | + |
| 31 | +## Solution |
| 32 | +To automatically select the first matching item in the ComboBox when the input loses focus, use a combination of the ComboBox [`OnRead` event](slug:components/combobox/events#onread) and JavaScript interop. The provided example demonstrates how to: |
| 33 | + |
| 34 | +1. Use the `OnRead` event to filter data and store the first matching item. |
| 35 | +2. Attach a JavaScript event handler to detect when the user blurs the ComboBox input. |
| 36 | +3. Invoke a .NET method from JavaScript to set the ComboBox value to the first matching item when focus is lost. |
| 37 | +4. Update the ComboBox selection programmatically and refresh the UI. |
| 38 | + |
| 39 | +>caption Auto-select the first matching item on blur |
| 40 | +
|
| 41 | +````RAZOR |
| 42 | +@using Telerik.DataSource.Extensions |
| 43 | +
|
| 44 | +@implements IDisposable |
| 45 | +
|
| 46 | +@inject IJSRuntime js |
| 47 | +
|
| 48 | +<p>ComboBoxFirstItem: @ComboBoxFirstItem?.Text</p> |
| 49 | +
|
| 50 | +<p>Selected value: @ComboBoxValue</p> |
| 51 | +
|
| 52 | +<TelerikComboBox OnRead="@OnComboBoxRead" |
| 53 | + TItem="@ListItem" |
| 54 | + TValue="@int" |
| 55 | + Value="@ComboBoxValue" |
| 56 | + ValueChanged="@( (int newValue) => ComboBoxValueChanged(newValue) )" |
| 57 | + TextField="@nameof(ListItem.Text)" |
| 58 | + ValueField="@nameof(ListItem.Id)" |
| 59 | + Filterable="true" |
| 60 | + FilterOperator="@StringFilterOperator.Contains" |
| 61 | + Placeholder="Select an item..." |
| 62 | + ShowClearButton="true" |
| 63 | + Width="200px" |
| 64 | + Id="combo-1"> |
| 65 | + <ComboBoxSettings> |
| 66 | + <ComboBoxPopupSettings Class="select-on-tab" /> |
| 67 | + </ComboBoxSettings> |
| 68 | +</TelerikComboBox> |
| 69 | +<br/> |
| 70 | +<br/> |
| 71 | +<TelerikTextBox Placeholder="Next form item" Width="200px"/> |
| 72 | +
|
| 73 | +@* Move JavaScript to a separate JS file *@ |
| 74 | +<script suppress-error="BL9992"> |
| 75 | + function attachComboKeyDown(selector) { |
| 76 | + var comboInput = document.querySelector(selector); |
| 77 | + if (comboInput) { |
| 78 | + comboInput.addEventListener("keydown", onComboInputKeyDown); |
| 79 | + } |
| 80 | + } |
| 81 | +
|
| 82 | + function detachComboKeyDown(selector) { |
| 83 | + var comboInput = document.querySelector(selector); |
| 84 | + if (comboInput) { |
| 85 | + comboInput.removeEventListener("keydown", onComboInputKeyDown); |
| 86 | + } |
| 87 | + } |
| 88 | +
|
| 89 | + function onComboInputKeyDown(e) { |
| 90 | + if (e.key == "Tab") { |
| 91 | + dotNet.invokeMethodAsync("OnComboBoxTab", e.target.value); |
| 92 | + } |
| 93 | + } |
| 94 | +
|
| 95 | + var dotNet; |
| 96 | +
|
| 97 | + function saveDotNetRef(dotNetRef) { |
| 98 | + dotNet = dotNetRef; |
| 99 | + } |
| 100 | +</script> |
| 101 | +
|
| 102 | +@code { |
| 103 | + private DotNetObjectReference<__Main>? DotNetRef { get; set; } |
| 104 | +
|
| 105 | + private List<ListItem> ComboBoxData { get; set; } = new(); |
| 106 | + private int ComboBoxValue { get; set; } |
| 107 | + private ListItem? ComboBoxFirstItem { get; set; } |
| 108 | +
|
| 109 | + [JSInvokable("OnComboBoxTab")] |
| 110 | + public void OnComboBoxTab(string newStringValue) |
| 111 | + { |
| 112 | + if (ComboBoxFirstItem is not null && ComboBoxFirstItem.Text.Contains(newStringValue)) |
| 113 | + { |
| 114 | + ComboBoxValue = ComboBoxFirstItem.Id; |
| 115 | + ComboBoxFirstItem = default; |
| 116 | +
|
| 117 | + StateHasChanged(); |
| 118 | + } |
| 119 | + } |
| 120 | +
|
| 121 | + private void ComboBoxValueChanged(int newValue) |
| 122 | + { |
| 123 | + ComboBoxValue = newValue; |
| 124 | + ComboBoxFirstItem = default; |
| 125 | + } |
| 126 | +
|
| 127 | + private async Task OnComboBoxRead(ReadEventArgs args) |
| 128 | + { |
| 129 | + var result = await ComboBoxData.ToDataSourceResultAsync(args.Request); |
| 130 | +
|
| 131 | + args.Data = result.Data; |
| 132 | + args.Total = result.Total; |
| 133 | +
|
| 134 | + if (args.Request.Filters.Count > 0) |
| 135 | + { |
| 136 | + ComboBoxFirstItem = args.Data.Cast<ListItem>().First(); |
| 137 | + } |
| 138 | + else |
| 139 | + { |
| 140 | + ComboBoxFirstItem = default; |
| 141 | + } |
| 142 | + } |
| 143 | +
|
| 144 | + protected override async Task OnAfterRenderAsync(bool firstRender) |
| 145 | + { |
| 146 | + if (firstRender) |
| 147 | + { |
| 148 | + await Task.Delay(1); // ensure HTML is ready |
| 149 | + await js.InvokeVoidAsync("saveDotNetRef", DotNetRef); |
| 150 | + await js.InvokeVoidAsync("attachComboKeyDown", "#combo-1"); |
| 151 | + } |
| 152 | +
|
| 153 | + await base.OnAfterRenderAsync(firstRender); |
| 154 | + } |
| 155 | +
|
| 156 | + protected override void OnInitialized() |
| 157 | + { |
| 158 | + DotNetRef = DotNetObjectReference.Create(this); |
| 159 | +
|
| 160 | + for (int i = 1; i <= 24; i++) |
| 161 | + { |
| 162 | + ComboBoxData.Add(new ListItem() |
| 163 | + { |
| 164 | + Id = i, |
| 165 | + Text = $"Item {i}" |
| 166 | + }); |
| 167 | + } |
| 168 | + } |
| 169 | +
|
| 170 | + public void Dispose() |
| 171 | + { |
| 172 | + DotNetRef?.Dispose(); |
| 173 | + _ = js.InvokeVoidAsync("detachComboKeyDown", "#combo-1"); |
| 174 | + } |
| 175 | +
|
| 176 | + public class ListItem |
| 177 | + { |
| 178 | + public int Id { get; set; } |
| 179 | + public string Text { get; set; } = string.Empty; |
| 180 | + } |
| 181 | +} |
| 182 | +```` |
| 183 | +## See Also |
| 184 | + |
| 185 | +- [ComboBox Events](slug:components/combobox/events) |
0 commit comments