From bd1fb27590d5d94f55682e703cd447461d0c3d5d Mon Sep 17 00:00:00 2001 From: Dimo Dimov <961014+dimodi@users.noreply.github.com> Date: Thu, 26 Mar 2026 14:55:20 +0200 Subject: [PATCH] kb(Grid): Fix broken keyboard navigation in Grid search example --- knowledge-base/grid-search-button-click.md | 93 ++++++++++++++++------ 1 file changed, 68 insertions(+), 25 deletions(-) diff --git a/knowledge-base/grid-search-button-click.md b/knowledge-base/grid-search-button-click.md index e7fe4f6bf3..c7772c1081 100644 --- a/knowledge-base/grid-search-button-click.md +++ b/knowledge-base/grid-search-button-click.md @@ -6,10 +6,11 @@ page_title: Search Grid Programmatically on Button Click slug: grid-kb-search-button-click position: tags: grid, search, gridsearchbox -ticketid: 1558540 +ticketid: 1707870, 1558540 res_type: kb components: ["grid"] --- + ## Environment @@ -21,19 +22,19 @@ components: ["grid"]
- ## Description I am using the Grid SearchBox, but I don't want it to search for every typed letter. I would like a button next to the search textbox set the search filter after the button is clicked. - ## Solution 1. [Bind the Grid with an OnRead event handler](slug:components/grid/manual-operations). -1. Replace the [**GridSearchBox**](slug:grid-searchbox) with a [TextBox](slug:components/textbox/overview) and a [Button](slug:components/button/overview) with an [OnClick event handler](slug:button-events). -1. Optionally, handle the [TextBox `OnChange` event](slug:components/textbox/events) too. This will allow searching on textbox blur and Enter keypress. +1. Replace the [**GridSearchBox**](slug:grid-searchbox) with a [TextBox](slug:components/textbox/overview) and a [Button](slug:components/button/overview) with an [`OnClick` event handler](slug:button-events). 1. In the click/change handler, build a [`CompositeFilterDescriptor`](slug:Telerik.DataSource.CompositeFilterDescriptor) with a `LogicalOperator` of `Or`. Populate its `FilterDescriptors` collection with filters for all searchable Grid model fields. 1. [Add the composite filter descriptor to the Grid State to search programmatically](slug:grid-state#setstateasync-examples). +1. (optional) Handle the [TextBox `OnChange` event](slug:components/textbox/events) too. This will allow searching on textbox blur and Enter keypress. +1. (optional) Wrap the search textbox in a `
` to enable the built-in Grid ToolBar keyboard navigation and achieve the same behavior as with the Telerik `GridSearchBox`. +1. (optional) Handle the `@onkeyup` event of the textbox wrapper `div` to clear the search value, similar to the Telerik `GridSearchBox`. Note the [difference between searching and filtering in the Grid state](slug:grid-state#information-in-the-grid-state). Filtering affects the Grid's filtering UI (row or menu), while searching does not. @@ -46,12 +47,21 @@ Also see the [Filter Descriptors documentation](slug:components/grid/filtering#f @using Telerik.DataSource.Extensions - +
+ + + + + +
Search Grid Clear Search
@@ -62,20 +72,39 @@ Also see the [Filter Descriptors documentation](slug:components/grid/filtering#f
@code { - List GridData { get; set; } = new List(); - TelerikGrid GridRef { get; set; } + private List GridData { get; set; } = new List(); + private TelerikGrid? GridRef; - string SearchValue { get; set; } + private string SearchValue { get; set; } = string.Empty; - async Task SearchGrid() + private async Task SearchGrid() { - var state = GridRef.GetState(); + if (SearchValue == string.Empty) + { + await ClearSearch(); + return; + } - var cfd = new CompositeFilterDescriptor(); - cfd.LogicalOperator = FilterCompositionLogicalOperator.Or; - cfd.FilterDescriptors = new FilterDescriptorCollection(); + GridState state = GridRef!.GetState(); + + CompositeFilterDescriptor? oldCfd = state.SearchFilter as CompositeFilterDescriptor; + if (oldCfd is not null) + { + FilterDescriptor? oldFd = oldCfd.FilterDescriptors.FirstOrDefault() as FilterDescriptor; + if (oldFd?.Value?.ToString() == SearchValue) + { + // Avoid duplicate data requests for the same search value. + return; + } + } + + CompositeFilterDescriptor cfd = new() + { + LogicalOperator = FilterCompositionLogicalOperator.Or, + FilterDescriptors = new FilterDescriptorCollection() + }; - // add one FilterDescriptor for each string column to search in + // Add one FilterDescriptor for each string column to search in. cfd.FilterDescriptors.Add(new FilterDescriptor() { @@ -92,21 +121,35 @@ Also see the [Filter Descriptors documentation](slug:components/grid/filtering#f }); state.SearchFilter = cfd; + await GridRef.SetStateAsync(state); } - async Task ClearSearch() + private async Task ClearSearch() { - var state = GridRef.GetState(); - state.SearchFilter = null; - await GridRef.SetStateAsync(state); + SearchValue = string.Empty; + + GridState state = GridRef!.GetState(); + + if (state.SearchFilter is not null) + { + state.SearchFilter = null; + await GridRef.SetStateAsync(state); + } + } - SearchValue = String.Empty; + private void OnTextBoxKeyUp(KeyboardEventArgs args) + { + // Simulate GridSearchBox behavior - clear the textbox on Escape key press. + if (args.Key == "Escape") + { + SearchValue = string.Empty; + } } - private async Task GridReadHandler(GridReadEventArgs args) + private async Task OnGridRead(GridReadEventArgs args) { - var result = GridData.ToDataSourceResult(args.Request); + DataSourceResult result = await GridData.ToDataSourceResultAsync(args.Request); args.Data = result.Data; args.Total = result.Total; } @@ -128,8 +171,8 @@ Also see the [Filter Descriptors documentation](slug:components/grid/filtering#f public class GridItem { public int ID { get; set; } - public string Name1 { get; set; } - public string Name2 { get; set; } + public string Name1 { get; set; } = string.Empty; + public string Name2 { get; set; } = string.Empty; } } ````