diff --git a/components/grid/filter/searchbox.md b/components/grid/filter/searchbox.md index 5f43d0c67..8086f7021 100644 --- a/components/grid/filter/searchbox.md +++ b/components/grid/filter/searchbox.md @@ -3,7 +3,7 @@ title: Toolbar SearchBox page_title: Grid - Filtering SearchBox description: Enable and configure filtering SearchBox in Grid for Blazor. slug: grid-searchbox -tags: telerik,blazor,grid,filtering,filter,searchbox +tags: telerik,blazor,grid,filtering,filter,searchbox,search published: True position: 20 --- @@ -72,7 +72,7 @@ To enable the SearchBox, add the `` tag in the [`caption Set and clear the SearchBox filter programmatically +>caption Set and clear the Grid SearchBox filter programmatically ````CSHTML @using Telerik.DataSource diff --git a/components/treelist/filter/images/search-box-overview.gif b/components/treelist/filter/images/search-box-overview.gif deleted file mode 100644 index 55f5cb583..000000000 Binary files a/components/treelist/filter/images/search-box-overview.gif and /dev/null differ diff --git a/components/treelist/filter/images/searchbox-filter-control.gif b/components/treelist/filter/images/searchbox-filter-control.gif deleted file mode 100644 index 852180b84..000000000 Binary files a/components/treelist/filter/images/searchbox-filter-control.gif and /dev/null differ diff --git a/components/treelist/filter/searchbox.md b/components/treelist/filter/searchbox.md index a2f11096d..4e5344d30 100644 --- a/components/treelist/filter/searchbox.md +++ b/components/treelist/filter/searchbox.md @@ -3,373 +3,254 @@ title: Toolbar Searchbox page_title: TreeList - Filtering Searchbox description: Enable and configure filtering Searchbox in TreeList for Blazor. slug: treelist-searchbox -tags: telerik,blazor,TreeList,filtering,filter,Searchbox +tags: telerik,blazor,treeList,filtering,filter,searchbox,search published: True position: 20 --- # TreeList Toolbar Searchbox -In addition to the [main filtering options]({%slug treelist-filtering%}), you can add a SearchBox in the TreeList Toolbar. +In addition to [TreeList filtering]({%slug treelist-filtering%}), you can also add a `SearchBox` in the [TreeList Toolbar]({%slug treelist-toolbar%}). The search box can filter in multiple TreeList columns at he same time. ->caption In this article: +>caption In this Article: * [Basics](#basics) -* [Filter From Code](#filter-from-code) +* [Search From Code](#search-from-code) * [Customize the SearchBox](#customize-the-searchbox) ## Basics -The SearchBox lets the user type their query and the TreeList will look up all visible string columns with a case-insensitive `Contains` operator, and filter them accordingly. You can change the filter delay, and the fields the TreeList will use - see the [Customize the SearchBox](#customize-the-searchbox) section below. +The SearchBox lets the user type their query and the TreeList will look up all visible `string` columns with a case-insensitive `Contains` operator, and filter them accordingly. To change the filter delay and the fields the TreeList will use, see the [Customize the SearchBox](#customize-the-searchbox) section below. -The SearchBox is independent from the standard filters. If you have filters applied, the SearchBox will respect them and add additional filtering criteria. Thus, you can also apply filtering to results returned from it. +The SearchBox is independent from the TreeList filtering. If the TreeList has applied filters, the SearchBox will respect them and add additional filtering criteria. Thus, you can also apply filtering to search results. -To enable the SearchBox, add the `` tag in the ``. +To enable the SearchBox, add the `` tag in the [``]({%slug treelist-toolbar%}). ->caption SearchBox in the Telerik TreeList +>caption TreeList SearchBox ````CSHTML -@* A search panel in the TreeList Toolbar *@ - - + - @* add this spacer to keep the searchbox on the right *@ - - - + + @code { - public List Data { get; set; } - - // sample model + private List TreeListData { get; set; } = new(); - public class Employee + protected override void OnInitialized() { - // hierarchical data collections - public List DirectReports { get; set; } - - // data fields for display - public int Id { get; set; } - public string Name { get; set; } - public string EmailAddress { get; set; } - } - - // data generation - - // used in this example for data generation and retrieval for CUD operations on the current view-model data - public int LastId { get; set; } = 1; - - protected override async Task OnInitializedAsync() - { - Data = await GetTreeListData(); - } - - async Task> GetTreeListData() - { - List data = new List(); - - for (int i = 1; i < 15; i++) + for (int i = 1; i <= 50; i++) { - Employee root = new Employee - { - Id = LastId, - Name = $"root: {i}", - EmailAddress = $"{i}@example.com", - DirectReports = new List(), - }; - data.Add(root); - LastId++; - - for (int j = 1; j < 4; j++) + TreeListData.Add(new SampleModel() { - int currId = LastId; - Employee firstLevelChild = new Employee - { - Id = currId, - Name = $"first level child {j} of {i}", - EmailAddress = $"{currId}@example.com", - DirectReports = new List(), - }; - root.DirectReports.Add(firstLevelChild); - LastId++; - - for (int k = 1; k < 3; k++) - { - int nestedId = LastId; - firstLevelChild.DirectReports.Add(new Employee - { - Id = LastId, - Name = $"second level child {k} of {j} and {i}", - EmailAddress = $"{nestedId}@example.com", - }); ; - LastId++; - } - } + Id = i, + ParentId = i <= 5 ? null : Random.Shared.Next(1, 6), + Name = $"{(char)(64 + i % 26 + 1)}{(char)(64 + i % 26 + 1)} {i}", + Description = $"{(char)(123 - i % 26 - 1)}{(char)(123 - i % 26 - 1)} {i}" + }); } + } - return await Task.FromResult(data); + public class SampleModel + { + public int Id { get; set; } + public int? ParentId { get; set; } + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; } } ```` ->caption The result from the code snippet above - -![treelist search box](images/search-box-overview.gif) - -## Filter From Code -You can set the TreeList filters programmatically through the component [state]({%slug treelist-state%}). - -@[template](/_contentTemplates/treelist/state.md#initial-state) +## Search From Code ->caption The result from the code snippet below. +You can set or remove the search filters programmatically through the `SearchFilter` property of the [TreeList state]({%slug treelist-state%}). -![Blazor TreeList Searchbox Filter Control](images/searchbox-filter-control.gif) +>caption Set and clear the TreeList SearchBox filter programmatically ->caption Set programmatically Searchbox Filter. - -````Razor -@* This snippet shows how to set filtering state to the TreeList from your code - Applies to the SearchBox filter *@ - -@using Telerik.DataSource; - -Set filtered state +````CSHTML +@using Telerik.DataSource - + Sortable="true"> + Search Programmatically + Clear Search - - - - + + @code { - public TelerikTreeList TreeListRef { get; set; } = new TelerikTreeList(); + private TelerikTreeList? TreeListRef { get; set; } - async Task SetTreeListFilter() + private List TreeListData { get; set; } = new(); + + private async Task OnSearchButtonClick() { - var filteredState = new TreeListState() + if (TreeListRef != null) { - SearchFilter = CreateSearchFilter() - }; + var treelistState = TreeListRef.GetState(); - await TreeListRef.SetStateAsync(filteredState); - } + var searchString = $"{(char)Random.Shared.Next(97, 123)}{(char)Random.Shared.Next(97, 123)}"; - private IFilterDescriptor CreateSearchFilter() - { - var descriptor = new CompositeFilterDescriptor(); - var fields = new List() { "Name", "Address" }; - var searchValue = "root: 1"; - descriptor.LogicalOperator = FilterCompositionLogicalOperator.Or; + var cfd = new CompositeFilterDescriptor(); - foreach (var field in fields) - { - var filter = new FilterDescriptor(field, FilterOperator.Contains, searchValue); + cfd.LogicalOperator = FilterCompositionLogicalOperator.Or; + cfd.FilterDescriptors = new FilterDescriptorCollection(); - filter.MemberType = typeof(string); + // Add one FilterDesccriptor for each string column + cfd.FilterDescriptors.Add(new FilterDescriptor() + { + Member = nameof(SampleModel.Name), + MemberType = typeof(string), + Operator = FilterOperator.Contains, + Value = searchString + }); + cfd.FilterDescriptors.Add(new FilterDescriptor() + { + Member = nameof(SampleModel.Description), + MemberType = typeof(string), + Operator = FilterOperator.Contains, + Value = searchString + }); - descriptor.FilterDescriptors.Add(filter); - } + treelistState.SearchFilter = cfd; - return descriptor; + await TreeListRef.SetStateAsync(treelistState); + } } - public List Data { get; set; } - - - public class Employee + private async Task OnClearButtonClick() { - public List DirectReports { get; set; } - - public int Id { get; set; } - public string Name { get; set; } - public string Address { get; set; } - public DateTime HireDate { get; set; } - } + if (TreeListRef != null) + { + var treelistState = TreeListRef.GetState(); - public int LastId { get; set; } = 1; + (treelistState.SearchFilter as CompositeFilterDescriptor)?.FilterDescriptors.Clear(); - protected override async Task OnInitializedAsync() - { - Data = await GetTreeListData(); + await TreeListRef.SetStateAsync(treelistState); + } } - async Task> GetTreeListData() + protected override void OnInitialized() { - List data = new List(); - - for (int i = 1; i < 15; i++) + for (int i = 1; i <= 500; i++) { - Employee root = new Employee + TreeListData.Add(new SampleModel() { - Id = LastId, - Name = $"root: {i}", - Address = $"{i}@example.com", - HireDate = DateTime.Now.AddYears(-i), - DirectReports = new List(), - }; - data.Add(root); - LastId++; - - for (int j = 1; j < 4; j++) - { - int currId = LastId; - Employee firstLevelChild = new Employee - { - Id = currId, - Name = $"first level child {j} of {i}", - Address = $"{currId}@example.com", - HireDate = DateTime.Now.AddDays(-currId), - DirectReports = new List(), - }; - root.DirectReports.Add(firstLevelChild); - LastId++; - - for (int k = 1; k < 3; k++) - { - int nestedId = LastId; - firstLevelChild.DirectReports.Add(new Employee - { - Id = LastId, - Name = $"second level child {k} of {j} and {i}", - Address = $"{nestedId}@example.com", - HireDate = DateTime.Now.AddMinutes(-nestedId) - }); ; - LastId++; - } - } + Id = i, + ParentId = i <= 5 ? null : Random.Shared.Next(1, 6), + Name = $"{(char)Random.Shared.Next(65, 91)}{(char)Random.Shared.Next(65, 91)} " + + $"{(char)Random.Shared.Next(65, 91)}{(char)Random.Shared.Next(65, 91)} {i}", + Description = $"{(char)Random.Shared.Next(97, 123)}{(char)Random.Shared.Next(97, 123)} " + + $"{(char)Random.Shared.Next(97, 123)}{(char)Random.Shared.Next(97, 123)} {i}" + }); } + } - return await Task.FromResult(data); + public class SampleModel + { + public int Id { get; set; } + public int? ParentId { get; set; } + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; } } ```` +@[template](/_contentTemplates/treelist/state.md#initial-state) + + ## Customize the SearchBox -The `TreeListSearchBox` component offers the following settings to customize its behavior: +The `TreeListSearchBox` component offers the following parameters to customize its behavior: @[template](/_contentTemplates/common/parameters-table-styles.md#table-layout) -| Attribute | Type and Default Value | Description | -|----------|----------|----------| -| `Class` | `string` | a CSS class rendered on the wrapper of the searchbox so you can customize its appearance. -| `DebounceDelay` | `int`
(300) |the time in milliseconds with which searching is debounced. Filtering does not happen on every keystroke and that can reduce the flicker for the end user. -| `Fields` |`List` | The collection of fields to search in. By default, the component looks in all string fields in its currently visible columns, and you can define a subset of that. -| `Placeholder` | `string`
(`Search...`(localized))| Specifies the placeholder attribute of the SearchBox component. -| `Width` | `string` | Specifies the width of the SearchBox component. +| Parameter | Type and Default Value | Description | +| --- | --- | --- | +| `Class` | `string`| The custom CSS class that renders on the SearchBox wrapper (``). | +| `DebounceDelay` | `int`
(`300`) | The time in milliseconds between the user typing ends and the search starts. Filtering does not occur on every keystroke during fast typing, unless `DebounceDelay` is set to `0`. | +| `Fields` | `List` | The collection of model properties to search in. By default, the TreeList searches in all visible columns that are bound to `string` fields. You can only define a subset of those fields. It is also possible to programmatically [search in `string` fields, which are not displayed in the TreeList]({%slug grid-kb-search-in-hidden-fields%}). | +| `Placeholder` | `string`
(`"Search..."`) | The textbox placeholder that hints the user what the SearchBox does. The built-in default value is [localized]({%slug globalization-localization%}). | +| `Width` | `string` | Specifies the width of the SearchBox component. | ->caption Customize the SearchBox to have a long filter delay, search in certain fields only and use a custom placeholder +The example below demonstrates all SearchBox settings in action, and also how to move the SearchBox on the opposite side of the TreeList toolbar. -````CSHTML -@* Increased delay, a subset of the columns are allowed for filtering and a custom placeholder *@ +>caption TreeList SearchBox customizaton - +````CSHTML + -
+ + Placeholder="Search Name Column..." + Width="240px" />
- - - + + -@code { - List SearchableFields = new List { "Name" }; - - List Data { get; set; } - - // sample model - - public class Employee - { - // hierarchical data collections - public List DirectReports { get; set; } - - // data fields for display - public int Id { get; set; } - public string Name { get; set; } - public string EmailAddress { get; set; } + - // data generation - - // used in this example for data generation and retrieval for CUD operations on the current view-model data - public int LastId { get; set; } = 1; +@code { + private List TreeListData { get; set; } = new(); - protected override async Task OnInitializedAsync() - { - Data = await GetTreeListData(); - } + private List SearchableFields = new List { nameof(SampleModel.Name) }; - async Task> GetTreeListData() + protected override void OnInitialized() { - List data = new List(); - - for (int i = 1; i < 15; i++) + for (int i = 1; i <= 50; i++) { - Employee root = new Employee - { - Id = LastId, - Name = $"root: {i}", - EmailAddress = $"{i}@example.com", - DirectReports = new List(), - }; - data.Add(root); - LastId++; - - for (int j = 1; j < 4; j++) + TreeListData.Add(new SampleModel() { - int currId = LastId; - Employee firstLevelChild = new Employee - { - Id = currId, - Name = $"first level child {j} of {i}", - EmailAddress = $"{currId}@example.com", - DirectReports = new List(), - }; - root.DirectReports.Add(firstLevelChild); - LastId++; - - for (int k = 1; k < 3; k++) - { - int nestedId = LastId; - firstLevelChild.DirectReports.Add(new Employee - { - Id = LastId, - Name = $"second level child {k} of {j} and {i}", - EmailAddress = $"{nestedId}@example.com", - }); ; - LastId++; - } - } + Id = i, + ParentId = i <= 5 ? null : Random.Shared.Next(1, 6), + Name = $"{(char)(64 + i % 26 + 1)}{(char)(64 + i % 26 + 1)} {i}", + Description = $"{(char)(123 - i % 26 - 1)}{(char)(123 - i % 26 - 1)} {i}" + }); } + } - return await Task.FromResult(data); + public class SampleModel + { + public int Id { get; set; } + public int? ParentId { get; set; } + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; } } ````