Telerik Forums
UI for Blazor Forum
1 answer
53 views

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), the OnRead 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>&nbsp;@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:

  1. Type some text in the autocomplete → OnRead is called ✅.

  2. 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?

Dimo
Telerik team
 updated answer on 18 Aug 2025
1 answer
33 views

Hello,

I noticed that when TelerikDatePicker and TelerikTimePicker components are used with nullable DateOnly and nullable TimeOnly values, respectively, and ShowClearButton is set to true, the "X" button still appears in an empty field when the value is null. This shouldn’t happen, as there is no value to clear. When you click on the field to type a date or time, the "X" button disappears.

Here is the reproduction of the issue:

https://blazorrepl.telerik.com/GfaCbmlz03hT2mky54

It doesn’t seem like this is intended behavior. If it’s not, is there a workaround to prevent the "X" from appearing when there is no value?

Thanks,

Ivaylo

 

Ivan Danchev
Telerik team
 answered on 15 Aug 2025
1 answer
34 views

When a user makes a selection in a dropdown in the first row of a Blazor Grid I want to be able to hide the same column in all the remaining rows to prevent them from making selections in those dropdowns. Is this possible?

 

George
Top achievements
Rank 1
Iron
 answered on 13 Aug 2025
1 answer
27 views

I'm getting this error when bound data list for a detail template is null

I don't have a Parameter 'source' in any model so don't understand what this is in reference to?

 

<DetailTemplate>
    <div class="form-group form-inline right">
        @{
            var bookingEquip = context as BookingEquipmentModel;
            <TelerikGrid @ref="@bookingEquipmentCommodityGridRef" 
                         Data="bookingEquip.Commodities"
                         Pageable="true"
                         PageSize="4"
                         Resizable="true"
                         Size="@ThemeConstants.Grid.Size.Small"
                         Width="90rem"
                         EditMode="@GridEditMode.Incell"
                         OnDelete="@((GridCommandEventArgs args) => OnCommodityDelete(args, bookingEquip))"
                         OnCreate="@((GridCommandEventArgs args) => OnCommodityCreate(args, bookingEquip))"
                         OnUpdate="@((GridCommandEventArgs args) => OnCommodityUpdate(bookingEquip, args))">
                <GridToolBarTemplate>
                    <!-- can only add a single commodity if there are none associated with this equipment) -->
                    <GridCommandButton Command="Add" Class="btn-green" Icon="@FontIcon.Plus" Enabled="@(!bookingEquip.Commodities.Any())">Add Commodity</GridCommandButton>
                </GridToolBarTemplate>
                <GridColumns>
                    <!-- Commodity Types -->
                    <GridColumn Field=@nameof(BookingEquipmentCommodityModel.CommodityType) Editable="true" Title="Description" Width="6rem">
                        <EditorTemplate Context="cbecContext">
                            @{
                                _currentBookingEquipmentCommodityModel = cbecContext as BookingEquipmentCommodityModel;
                                if (_currentBookingEquipmentCommodityModel != null)
                                {
                                    <TelerikDropDownList Data="@_CommodityList"
                                                         Value="@_currentBookingEquipmentCommodityModel.CommodityTypeId"

for the Data reference, bookingEquip is NOT null but it's property bookingEquip.Commodities is indeed null (expected).

The grid displays correctly, but as soon as I click on the "+" expand it will crash with exception in the control.

I'm puzzled as to why this is happening?  When I populate other grids (not using a DetailTemplate) in my Blazor app, and the Data reference is a null, nothing is displayed/render in the grid and I just get a "No records available." ... which is good.  But the same behavior doesn't seem to happen when using DetailTemplate?

Any suggestions?

Rob.

 

 

 

Rob
Top achievements
Rank 3
Bronze
Bronze
Iron
 answered on 11 Aug 2025
1 answer
80 views
I use "Telerik.UI.for.Blazor 9.1.0" for build Blazor application. And I need to create "Collapse panel" can you sugget me solution using "Telerik.UI.for.Blazor 9.1.0" components. I have researched all available components of the "Telerik.UI.for.Blazor 9.1.0" in source code and documentations (manual) as result I cannot find any mention about "ExpansionPanel" or "Collapse panel" or "Accordion" or other similar panels or components which allow open or Collapse content.

I need to use  "Collapse panel" which will be default close and user could open it. Content of my "Collapse panel" is going to be form inputs or other elements. When user opens "Collapse panel" first time I need to make request for load a lot of data  for my form (inputs, dropdown lists, etc.) in this way I need to show loader/spinner during i try to load and compute my form data.

Key point of the "Accordion Collapse panel" :
1) User can open and close "Accordion Collapse panel";
2) User can set default state of the "Accordion Collapse panel"  - open or close;
3) "Accordion Collapse panel"  has events for open "Accordion Collapse panel"  and close "Accordion Collapse panel"  and other events;
4) For long calculation and computing my "Accordion Collapse panel"  has ability to show loader/spinner;
5) "Accordion Collapse Panel" has some expanded mode which  can allow user only one Accordion Panel item to be expanded at a time or any Accordion Panels can expanded at the same time;

Could you help me with this solution  of the "Collapse panel" ?

Alexey
Top achievements
Rank 1
Iron
 answered on 10 Aug 2025
1 answer
36 views

If I want to restrict the number of selected rows to just three, can I do this with a configuration or a property?  I am looking at the following demo.  Thanks!

https://demos.telerik.com/blazor-ui/grid/row-selection

Hristian Stefanov
Telerik team
 answered on 07 Aug 2025
1 answer
28 views

hi,

 

C:\SQ_AzureDevOps\BlazorApp1\BlazorApp1>dotnet nuget remove source telerik.com
La source de package nommée telerik.com a été correctement supprimée.

C:\SQ_AzureDevOps\BlazorApp1\BlazorApp1>dotnet nuget add source "https://nuget.telerik.com/v3/index.json" --name telerik.com --username "...@..." --password "....." --store-password-in-clear-text
La source de package nommée telerik.com a été correctement ajoutée.

C:\SQ_AzureDevOps\BlazorApp1\BlazorApp1>dotnet add package Telerik.UI.for.Blazor

Générer a réussi dans 0,7s
info : La validation de la chaîne de certificats X.509 utilisera le magasin de confiance par défaut sélectionné par .NET pour le code de signature.
info : La validation de la chaîne de certificats X.509 utilisera le magasin de confiance par défaut sélectionné par .NET pour le timestamp.
info : Ajout de PackageReference pour le package 'Telerik.UI.for.Blazor' dans le projet 'C:\SQ_AzureDevOps\BlazorApp1\BlazorApp1\BlazorApp1.csproj'.
error: Impossible de charger l'index de service pour la source https://nuget.telerik.com/v3/index.json.
error:   Response status code does not indicate success: 401 (Unauthorized).

So, its a Trial account nothing wrog with th API-KEY being visible here, but I dont fink I do something wrong, do I?

Dimo
Telerik team
 answered on 07 Aug 2025
1 answer
44 views

I am using the TelerikUpload component.
Telerik.UI.for.Blazor version 9.0.0

Extra security checks (anti-virus etc.) are triggered in the Controller and depending on what caused an issue, I would like to change the default "File failed to upload" error message. Ideally this message would be set in the OnError handler, or maybe a ChildTemplate exists I am not aware of?

 This post talks about changing the message through localization, but that does not allow me to change it at runtime:

Dimo
Telerik team
 answered on 04 Aug 2025
1 answer
38 views
Hi Telerik Team,
Telerik is the best! Keep growing!

I'm using Telerik Blazor Grid with server-side grouping, and I’m manually group returned JSON structure with AggregateFunctionsGroup. I'm deserializing the result using a helper like this:


public static List<AggregateFunctionsGroup>? DeserializeGroups<TGroupItem>(this List<AggregateFunctionsGroup> groups)
{
    if (groups is null) return null;

    for (int i = 0; i < groups.Count; i++)
    {
        var group = groups[i];

        // Workaround for JsonElement -> string
        if (group.Key is JsonElement elem && elem.ValueKind == JsonValueKind.String)
        {
            group.Key = elem.GetString();
        }

        if (group.HasSubgroups)
        {
            var subGroups = group.Items
                .Cast<JsonElement>()
                .Select(x => x.Deserialize<AggregateFunctionsGroup>())
                .ToList();

            group.Items = DeserializeGroups<TGroupItem>(subGroups);
        }
        else
        {
            var items = group.Items
                .Cast<JsonElement>()
                .Select(x => x.Deserialize<TGroupItem>())
                .ToList();

            group.Items = items;
        }
    }

    return groups;
}
And just for some context:

public async Task ReadItems(GridReadEventArgs args)
{
    if (!ModelIsReady) return;
    if (_readItemsPending) return;
    if (string.IsNullOrWhiteSpace(PreparedQuery.Id)) return;
    _readItemsPending = true;

    try
    {
        var result = await ApiService.QueryDataSourceAsync<UniversalDSModel>(PreparedQuery.QueryId, args.Request, CancellationToken.None);
        if (result is null) return;

        if (args.Request.Groups.Count > 0)
        {
            args.Data = result?.GroupedData.DeserializeGroups<UniversalDSModel>();
        }
        else
        {
            args.Data = result?.CurrentPageData.Cast<object>().ToList();
        }

        if (result?.AggregateResults != null)
        {
            args.AggregateResults = result.AggregateResults;
        }

        if (result != null) { args.Total = result.TotalItemCount; }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error loading data: {ex.Message}");
        ApiRequestFailed = true;
    }
    finally
    {
        _readItemsPending = false;
        LoaderContainerVisible = false;
    }
}


My main concern:
group.Key always arrives from the backend as a JsonElement, so we have to inspect the ValueKind manually to convert it (e.g. to string).
This feels fragile — what if the key is a bool, int, DateTime, or some complex object, is it converted to string no matter what - for grouping???
Without additional metadata, it's hard to confidently deserialize Key to its intended type.

My question:
Is this the expected approach for deserializing grouped data with AggregateFunctionsGroup?
Would you consider adding a KeyType or some metadata in the grouped result to help with type-safe deserialization?
Is there a recommended way to deserialize group.Key if the grouping field can vary in type (e.g., string, int, bool)?
Thanks in advance — just want to ensure I’m handling this correctly and not missing a simpler or more robust pattern.

Best regards,
Bohdan
Dimo
Telerik team
 answered on 04 Aug 2025
0 answers
28 views

so issue was when i uploading file that still in upload phase if i click the cancel button next upload progress bar the file is removes from ui but somewhere is still present 

so i have used OnSelectHandler event to handle to duplicate uploading and some extra validation added in OnSelectHandler event but my issue is

when i am uploading file and immediately click [ Before upload process is done ] cancel then it remove from ui but somewhere is present after that remove click again try to add show my validation error that is duplicate message 


Expected Result- 

Clicking Cancel should stop the upload process entirely, and no file should be uploaded or stored.

Please Refer Below Attachment 

Step 1 => Select file eg. dummy.pdf and select Note : AutoUpload is true and check below screenshot and i click cancel button 

 

Step 2 => The file removed from UI see below screenshot




Step 3 => If i try to add again same file i.e dummy.pdf the my custom validation msg show that is file is already present see below screenshot





Below is My Code :

 <TelerikUpload DropZoneId="dropzone-id" @ref="@UploadRef" Id="uploadFile"
                SaveUrl="@UploadSaveUrlPath"
                Class="@UploadClass"
                OnSuccess="@OnUploadSuccess"
                OnRemove="@OnUploadRemove"
                OnError="@OnUploadError"
                OnProgress="@OnUploadProgress"
                Multiple="true"
                OnSelect="@OnSelectHandler" >
     
 </TelerikUpload>

  private async void OnUploadSuccess(UploadSuccessEventArgs args)
  {
      if (args.Operation != UploadOperationType.Upload) return;

      isUploadedSuccess = true;
      uploadedInfoCache = await LoadUploadedFilesAsync();

      foreach (var file in args.Files)
      {
          var match = uploadedInfoCache?.FirstOrDefault(f =>
              f.FileName == file.Name &&
              f.Size == file.Size);

          if (match != null)
          {
              file.Id = match.FileId; // Set ID for later removal
          }
      }
  }

  private void OnUploadError(UploadErrorEventArgs e) => isUploadedSuccess = false;

  private async Task OnSelectHandler(UploadSelectEventArgs e)
  {
      // Early exit if already full
      if (selectedFiles.Count > MaxAttachmentFile)
          return;

      foreach (var file in e.Files.ToList())
      {
          // 1. Check max file size
          if (file.Size > MaxFileSize * 1024 * 1024)
          {
              await DialogSvc.AlertAsync(Resources.Attachments,
                  string.Format(Resources.MaxAllowedFileSizeShould, MaxFileSize, Math.Ceiling((double)file.Size / 1024 / 1024)));

              e.Files.Remove(file); // exclude large file
              continue;
          }

          // 2. Check for duplicate name (uploaded or selected)
          bool isDuplicate = Attachments.Any(a => a.FileName.Equals(file.Name, StringComparison.OrdinalIgnoreCase)) ||
                             selectedFiles.Any(a => a.Name.Equals(file.Name, StringComparison.OrdinalIgnoreCase));

          if (isDuplicate)
          {
              await DialogSvc.AlertAsync(Resources.TitleDuplicateAttachment,
                  string.Format(Resources.DuplicateAttachmentMsg, file.Name));

              e.Files.Remove(file); // exclude duplicate
          }
      }

      // 3. File count check after all filtering
      if (selectedFiles.Count + e.Files.Count > MaxAttachmentFile)
      {
          e.IsCancelled = true;
          await DialogSvc.AlertAsync(Resources.MaxFileUploadedTitle, MaxFileErrorMsg);
          return;
      }

      // 4. Add only valid files
      selectedFiles.AddRange(e.Files);

      // 5. Final file-level validations
      isUploadedSuccess = e.Files.All(file =>
          !file.InvalidExtension &&
          !file.InvalidMinFileSize &&
          !file.InvalidMaxFileSize);
  }

 private async void OnUploadRemove(UploadEventArgs args)
 {
     foreach (var file in args.Files)
     {
         selectedFiles.RemoveAll(f => f.Id == file.Id);

         var match = uploadedInfoCache.FirstOrDefault(f => f.FileName == file.Name && f.Size == file.Size);
         if (match == null) continue;

         var content = new FormUrlEncodedContent(new[]
         {
             new KeyValuePair<string, string>("fileId", match.FileId)
         });

         await HttpClient.PostAsync(ToAbsoluteUrl(RemoveFileUrlPath), content);
     }

     if (!selectedFiles.Any())
     {
         UploadRef.ClearFiles();
         await HttpClient.GetAsync(ToAbsoluteUrl(CleanFilesUrlPath));
     }
 }

Vaibhav
Top achievements
Rank 1
Iron
Iron
 asked on 01 Aug 2025
Narrow your results
Selected tags
Tags
+? more
Top users last month
Rob
Top achievements
Rank 3
Bronze
Bronze
Iron
Sergii
Top achievements
Rank 1
Iron
Iron
Dedalus
Top achievements
Rank 1
Iron
Iron
Lan
Top achievements
Rank 1
Iron
Doug
Top achievements
Rank 1
Want to show your ninja superpower to fellow developers?
Top users last month
Rob
Top achievements
Rank 3
Bronze
Bronze
Iron
Sergii
Top achievements
Rank 1
Iron
Iron
Dedalus
Top achievements
Rank 1
Iron
Iron
Lan
Top achievements
Rank 1
Iron
Doug
Top achievements
Rank 1
Want to show your ninja superpower to fellow developers?
Want to show your ninja superpower to fellow developers?