I am using the TelerikAutoComplete component in Blazor with a custom OnRead
function to fetch items from a data source. The issue I am facing is:
When I type in the search box,
OnRead
executes as expected.But when I erase the search text (set it back to
null
or empty string), theOnRead
function is not triggered.
My expectation is that when the input is cleared, OnRead
should fire again so that I can refresh the data (or return an empty dataset).
<TelerikAutoComplete @ref="@autoCompleteRef"
TItem="@AutoCompleteLookupItem"
Id="@Id"
OnRead="@ReadItems"
DebounceDelay="@DebounceTimeMs"
Filterable="@true"
Placeholder="@Placeholder"
FilterOperator="@FilterOperator"
ValueField="@(nameof(AutoCompleteLookupItem.SelectedValue))"
Value="@Value"
ValueExpression="@( () => Value )"
OnChange="HandleValueConfirmation"
ValueChanged="@HandleValueChanged"
Enabled="IsEnabled"
Class="@Class"
OnBlur="@OnFocusLoose">
<ItemTemplate>
@if (!string.IsNullOrWhiteSpace(@context.SelectedValue))
{
@if (context.Hints == null || !context.Hints.Any())
{
//If we do not have any hints. Display only values
@if (context.Value.Key == "--")
{
//Do not display label. Only display value
<span id="value">@context.SelectedValue</span>
}
else
{
//Display both label and value
<span id="label-and-value">@context.Value.Key: @context.SelectedValue</span>
}
}
else if (context.Hints.Count == 1)
{
//If we only have single hint. Display value along with hint.
<span id="value-with-hint">
<strong>@context.SelectedValue</strong>
@if (!string.IsNullOrWhiteSpace(@context.Hints.First().Value))
{
<i> @context.Hints.First().Value</i>
}
</span>
}
else if (context.Hints.Count == 2)
{
@if (string.IsNullOrWhiteSpace(this.Value) || !LookupBehavior.HasFlag(LookupBehavior.HighlightUserInput))
{
<span id="has-empty-value">
<span id="first-hint">@context.Hints.ElementAt(0).Key: @context.Hints.ElementAt(0).Value<br /></span>
<span id="selected-value">@context.Value.Key: @context.SelectedValue <br /></span>
<span id="second-hint">@context.Hints.ElementAt(1).Key: @context.Hints.ElementAt(1).Value</span>
</span>
}
else
{
<span id="has-value">
<span id="first-hint">@context.Hints.ElementAt(0).Key: @UIUtilities.HighlightUserInputWithBoldTags(HttpUtility.HtmlEncode(@context.Hints.ElementAt(0).Value), HttpUtility.HtmlEncode(this.Value)) <br /></span>
<span id="selected-value">@context.Value.Key: @UIUtilities.HighlightUserInputWithBoldTags(HttpUtility.HtmlEncode(@context.SelectedValue), HttpUtility.HtmlEncode(this.Value)) <br /></span>
<span id="second-hint">@context.Hints.ElementAt(1).Key: @UIUtilities.HighlightUserInputWithBoldTags(HttpUtility.HtmlEncode(@context.Hints.ElementAt(1).Value), HttpUtility.HtmlEncode(this.Value))</span>
</span>
}
}
}
</ItemTemplate>
</TelerikAutoComplete>
<div class="icons">
@if (IsEnabled)
{
<span>
<a id="search-link" @onclick="@OpenAutoComplete" title="search">
<svg class="icon" aria-hidden="true" focusable="false">
<use xlink:href="icons/ece-sprite.svg#ece-icon-search"></use>
</svg>
</a>
</span>
}
else
{
<span class="disable-links">
<a id="search-disabled-link">
<svg class="icon" aria-hidden="true" focusable="false">
<use xlink:href="icons/ece-sprite.svg#ece-icon-search"></use>
</svg>
</a>
</span>
}
</div>
</div>
@if (ShowRequiredMessage && !string.IsNullOrWhiteSpace(RequiredMessage))
{
<span id="required-message" class="k-form-error k-invalid-msg ">
@RequiredMessage
</span>
}
@code {
[Parameter]
public string Id { get; set; }
[Parameter]
public string Placeholder { get; set; }
[Parameter]
public EventCallback<string> ValueChanged { get; set; }
[Parameter]
public string BoundField { get; set; }
[Parameter]
public EventCallback<string> ValueConfirmed { get; set; }
[Parameter]
public string Value { get; set; }
[Parameter]
public LookupBehavior LookupBehavior { get; set; } = LookupBehavior.None;
[Parameter]
public int DebounceTimeMs { get; set; } = 500;
[Parameter]
public int InitialSkip { get; set; } = 0;
[Parameter] public Func<string, Task<List<AutoCompleteLookupItem>>> FilterMethod { get; set; }
[Parameter]
public StringFilterOperator FilterOperator { get; set; }
[Parameter]
public string? RequiredMessage { get; set; }
[Parameter]
public bool IsEnabled { get; set; } = true;
[Parameter]
public string Class { get; set; }
public bool ShowRequiredMessage { get; set; }
private List<AutoCompleteLookupItem> dataSource;
private TelerikAutoComplete<AutoCompleteLookupItem> autoCompleteRef { get; set; }
private string lastValue;
private bool lostFocus;
async Task ReadItems(AutoCompleteReadEventArgs args)
{
string userInput = string.Empty;
if (args.Request.Filters.Count > 0)
{
Telerik.DataSource.FilterDescriptor filter = args.Request.Filters[0] as Telerik.DataSource.FilterDescriptor;
userInput = filter.Value.ToString();
}
if (lastValue != userInput)
{
if (!lostFocus)
{
lastValue = userInput;
args.Data = await FilterMethod.Invoke(userInput);
}
else
{
lastValue = this.Value;
args.Data = await FilterMethod.Invoke(lastValue);
lostFocus = false;
}
}
}
private void OnFocusLoose() => lostFocus = true;
private async Task HandleValueConfirmation(object userChoice)
{
string currentValue = (string)userChoice;
if (LookupBehavior.HasFlag(LookupBehavior.TriggerActionOnValueConfirmation))
{
if (currentValue != lastValue)
{
await ValueConfirmed.InvokeAsync((currentValue) ?? string.Empty);
lastValue = currentValue;
}
}
if (LookupBehavior.HasFlag(LookupBehavior.ValidateOnValueConfirmation))
{
if (ValueConfirmed.HasDelegate)
ValueConfirmed.InvokeAsync(BoundField);
ShowRequiredMessage = string.IsNullOrEmpty(this.Value) && !string.IsNullOrEmpty(RequiredMessage);
}
await ValueConfirmed.InvokeAsync((currentValue) ?? string.Empty);
}
async Task OpenAutoComplete()
{
await autoCompleteRef.FocusAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
<!--
Below script is used for opening the autocomplete suggestion upon clicking Search Icon
-->
await js.InvokeVoidAsync("TelerikTweaks.attachFocusHandler", autoCompleteRef.Id, ".k-autocomplete");
}
await base.OnAfterRenderAsync(firstRender);
}
private async Task HandleValueChanged(object newValue)
{
this.Value = (string)newValue;
await ValueChanged.InvokeAsync(this.Value);
}
}
Steps to Reproduce:
Type some text in the autocomplete →
OnRead
is called ✅.Erase the text so the input becomes empty (
null
or""
) →OnRead
is not called ❌.
Question:
Is this the expected behavior? If so, how can I force the autocomplete to execute OnRead
when the input text is cleared (so I can refresh my dataset)?
Do I need to hook into another event (ValueChanged
, OnChange
, etc.) to manually call ReadItems
in this case?