Unplanned
Last Updated: 25 Jan 2021 08:26 by ADMIN
Created by: Jürgen
Comments: 0
Category: Grid
Type: Feature Request
16
I would like to be able to reposition the Grid Toolbar, for example, to move it to the bottom of the Grid. 
Unplanned
Last Updated: 12 Jul 2022 06:51 by ADMIN
Created by: SaiSivaSankar
Comments: 1
Category: Grid
Type: Feature Request
15
I would like to exclude the group header from the horizontal scroll - that is, the group header must always be visible regardless of how the user scrolls the grid left and right, like a Locked column.
Unplanned
Last Updated: 17 May 2022 07:50 by ADMIN
Created by: Steven
Comments: 4
Category: Grid
Type: Feature Request
15

Add a setting similar to the AllowUnsort so that I can disable the unsorted state of the Grid.

ADMIN EDIT:

Here is how to achieve this with the Grid state.

Unplanned
Last Updated: 03 Feb 2025 17:41 by Simi

I am using this sample to implement server-side grouping:

https://github.com/telerik/blazor-ui/tree/master/grid/datasourcerequest-on-server/WasmApp

Now I need Aggregate sum for the price in the GroupFooterTemplate. When I add aggregates, exceptions are thrown if a group footer uses the aggregate value, if not - the grid simply does not look grouped.

---

ADMIN EDIT

The issue stems from the inability of the System.Text.Json to deserialize interfaces - there are a couple of interfaces in the datasource request and data source result related to aggregates. Preliminary review indicates that perhaps some or all of them might be changed to, for example, Dictionary<string, object> from the current IDictionary<string, object>, or perhaps the framework might "learn" to deserialize interfaces.

----

Unplanned
Last Updated: 21 Mar 2024 08:06 by Domenico

Please expose an option to configure the field delimiter for CSV export. I want to set semicolon as field delimiter instead of a comma.

---

ADMIN EDIT

---

Internally the Grid uses SpreadStreamProcessing library to perform the export. That said, a necessary prerequisite to implement the current enhancement is that SpreadStreamProcessing supports settings for changing the delimiter when exporting to CSV. You may vote for the item and follow it to get status email updates.

For the time being, you may customize the exported file to set the desired field separator as suggested in the Grid CSV export - change the comma field delimiter knowledge base article.

Unplanned
Last Updated: 11 Jun 2021 11:52 by ADMIN
Created by: Walter
Comments: 0
Category: Grid
Type: Feature Request
12
I would like to be able to customize the Drag Clue with a Template. 
Unplanned
Last Updated: 13 Apr 2022 07:16 by ADMIN

I would like to request a simple update to the Grid component.

When a column width is too small - the column header text is cut-off or is unreadable.

For example:

It would be nice that on mouse hover, the full title would be rendered. Currently to achieve this, I have to implement a custom <HeaderTemplate> for every grid column and add a span myself:

<GridColumn Field="@nameof(SalesOrderLineItem.Quantity)">
    <HeaderTemplate>
        <span title="Order Quantity">Order Quantity</span>
    </HeaderTemplate>
</GridColumn>

 

Can you update the GridColumn component and add a title attribute to the column <th> element so the browser can show the fill title should the user hover over it?

 

Unplanned
Last Updated: 11 Nov 2022 11:36 by

The Grid selection performance is worse in WASM when there is a command column. Here is a test page with a large page size, which makes this more evident.

<label><TelerikCheckBox @bind-Value="@ShowCommandColumn" /> Show Command Column</label>

<TelerikGrid Data="@DataList"
             SelectionMode="@GridSelectionMode.Single"
             Height="700px">
    <GridColumns>
        <GridColumn Field="@(nameof(DataModel.Pos))" Title="Pos" />
        @if (ShowCommandColumn)
        {
            <GridCommandColumn Width="300px">
                <GridCommandButton Command="Save" Icon="save">Reset Volume</GridCommandButton>
                <GridCommandButton Command="Delete" Icon="delete">Delete</GridCommandButton>
            </GridCommandColumn>
        }
    </GridColumns>
</TelerikGrid>

@code {

    bool ShowCommandColumn { get; set; } = true;

    List<DataModel> DataList { get; set; }

    protected override async Task OnInitializedAsync()
    {
        DataList = new List<DataModel>();
        for (int i = 1; i <= 500; i++)
        {
            DataList.Add(new DataModel
            {
                Pos = i
            });
        }
    }

    public class DataModel
    {
        public int Pos { get; set; }
    }
}

 

Unplanned
Last Updated: 31 Aug 2020 09:20 by ADMIN
Created by: Datafyer
Comments: 2
Category: Grid
Type: Feature Request
11

Would be helpful to have the feature of copying selected row to the clipboard.

The copy format could be CSV or just tabbed delimiter.

---

ADMIN EDIT

In the meantime, you can consider your own JS-based solution (example StackOverflow thread) and integrate them on a command button in the grid or in the row context menu.

---

Unplanned
Last Updated: 18 Aug 2023 15:43 by Greg
I would like to be able to use complex models (such as those generated from CSLA.NET) for the Grid. 
Unplanned
Last Updated: 05 Aug 2024 14:48 by Nicholas
I want to take a row and move the mouse while holding the row at the bottom of the screen and it scrolls.  Is this feature available?  This is built in for an HTML grid.
Unplanned
Last Updated: 17 Nov 2021 16:01 by Nemo
Created by: Christian
Comments: 7
Category: Grid
Type: Feature Request
10
I would like to use Virtual Scrolling and Hierarchy for the Grid. 
Unplanned
Last Updated: 01 Sep 2021 14:26 by ADMIN
Created by: BENAISSA
Comments: 0
Category: Grid
Type: Feature Request
10
I would like to customize the column menu for the Grid. Also, I want to change the default order of the Colum Menu built-in items. For example:
<ColumnMenuTemplate>
<CustomColumnMenuItem/>
<ColumnMenuFiltering/>
<ColumnMenuSorting/>
....
</ColumnMenuTemplate>
Unplanned
Last Updated: 04 Dec 2024 13:35 by ADMIN
Created by: Jeff
Comments: 1
Category: Grid
Type: Feature Request
10
I would like to refresh the contents of the FilterMenu from my application code. 
Unplanned
Last Updated: 17 Oct 2023 07:05 by Israel
Created by: Israel
Comments: 0
Category: Grid
Type: Feature Request
9

The TelerikCheckBoxListFilter starts working very slowly with hundreds of items or more. That includes rendering and searching in it.

A possible workaround is to put a virtual Grid inside the FilterMenuTemplate. The example below is a modified version of this one - Blazor Grid checkbox list filtering with custom data. The FilterMenuButtonsTemplate is necessary to clear the selected Grid rows when the user clears the column filter.

@using Telerik.DataSource
@using Telerik.DataSource.Extensions

<TelerikGrid TItem="@Employee"
             OnRead="@OnReadHandler"
             Pageable="true"
             FilterMode="@( NameOptions != null ? GridFilterMode.FilterMenu : GridFilterMode.None )"
             FilterMenuType="@FilterMenuType.CheckBoxList"
             Height="400px">
    <GridColumns>
        <GridColumn Field="@(nameof(Employee.EmployeeId))" Filterable="false" />
        <GridColumn Field="@nameof(Employee.Name)">
            <FilterMenuTemplate Context="context">
                <TelerikGrid Data="@NameOptions"
                             ScrollMode="@GridScrollMode.Virtual"
                             Height="240px"
                             RowHeight="36"
                             FilterMode="@GridFilterMode.FilterRow"
                             SelectionMode="@GridSelectionMode.Multiple"
                             SelectedItems="@SelectedGridItems"
                             SelectedItemsChanged="@( (IEnumerable<NameFilterOption> newSelected) =>
                                                      GridSelectedItemsChanged(newSelected, context.FilterDescriptor) )">
                    <GridColumns>
                        <GridCheckboxColumn SelectAllMode="@GridSelectAllMode.All" />
                        <GridColumn Field="@nameof(NameFilterOption.Name)"></GridColumn>
                    </GridColumns>
                </TelerikGrid>
            </FilterMenuTemplate>
            <FilterMenuButtonsTemplate Context="filterContext">
                <TelerikButton OnClick="@(async _ => await filterContext.FilterAsync())"
                               ThemeColor="@ThemeConstants.Button.ThemeColor.Primary">Filter </TelerikButton>
                <TelerikButton OnClick="@(() => ClearFilterAsync(filterContext))">Clear</TelerikButton>
            </FilterMenuButtonsTemplate>
        </GridColumn>
        <GridColumn Field="@nameof(Employee.Team)" Title="Team" />
        <GridColumn Field="@nameof(Employee.IsOnLeave)" Title="On Vacation" />
    </GridColumns>
</TelerikGrid>

@code {
    string DDLValue { get; set; }
    List<Employee> AllGridData { get; set; }

    private IEnumerable<NameFilterOption> SelectedGridItems { get; set; } = new List<NameFilterOption>();

    private void GridSelectedItemsChanged(IEnumerable<NameFilterOption> newSelectedItems, CompositeFilterDescriptor cfd)
    {
        SelectedGridItems = newSelectedItems;
        cfd.LogicalOperator = FilterCompositionLogicalOperator.Or;
        cfd.FilterDescriptors.Clear();
        foreach (var sgi in SelectedGridItems)
        {
            cfd.FilterDescriptors.Add(new FilterDescriptor()
            {
                Member = nameof(Employee.Name),
                MemberType = typeof(string),
                Operator = FilterOperator.IsEqualTo,
                Value = sgi.Name
            });
        }
    }

    private async Task ClearFilterAsync(FilterMenuTemplateContext filterContext)
    {
        SelectedGridItems = new List<NameFilterOption>();
        await filterContext.ClearFilterAsync();
    }

    #region custom-filter-data
    List<TeamNameFilterOption> TeamsList { get; set; }
    List<NameFilterOption> NameOptions { get; set; }

    //obtain filter lists data from the data source to show all options
    async Task GetTeamOptions()
    {
        if (TeamsList == null) // sample of caching since we always want all distinct options,
                               //but we don't want to make unnecessary requests
        {
            TeamsList = await GetNamesFromService();
        }
    }

    async Task<List<TeamNameFilterOption>> GetNamesFromService()
    {
        await Task.Delay(500);// simulate a real service delay

        // this is just one example of getting distinct values from the full data source
        // in a real case you'd probably call your data service here instead
        // or apply further logic (such as tie the returned data to the data the grid will have according to your business logic)
        List<TeamNameFilterOption> data = AllGridData.OrderBy(z => z.Team).Select(z => z.Team).
            Distinct().Select(t => new TeamNameFilterOption { Team = t }).ToList();

        return await Task.FromResult(data);
    }

    async Task GetNameOptions()
    {
        if (NameOptions == null)
        {
            NameOptions = await GetNameOptionsFromService();
        }
    }

    async Task<List<NameFilterOption>> GetNameOptionsFromService()
    {
        await Task.Delay(500);// simulate a real service delay

        List<NameFilterOption> data = AllGridData.OrderBy(z => z.Name).Select(z => z.Name).
            Distinct().Select(n => new NameFilterOption { Name = n }).ToList();

        return await Task.FromResult(data);
    }
    #endregion custom-filter-data

    async Task OnReadHandler(GridReadEventArgs args)
    {
        //typical data retrieval for the grid
        var filteredData = await AllGridData.ToDataSourceResultAsync(args.Request);
        args.Data = filteredData.Data as IEnumerable<Employee>;
        args.Total = filteredData.Total;
    }

    protected override async Task OnInitializedAsync()
    {
        // generate data that simulates the database for this example
        // the actual grid data is retrieve in its OnRead handler
        AllGridData = new List<Employee>();
        var rand = new Random();
        for (int i = 1; i <= 1000; i++)
        {
            AllGridData.Add(new Employee()
            {
                EmployeeId = i,
                Name = "Employee " + i.ToString(),
                Team = "Team " + i % 3,
                IsOnLeave = i % 2 == 0
            });
        }

        // get custom filters data. In a future version you will be able to call these methods
        // from the template initialization instead of here (or in OnRead) so that they fetch data
        // only when the user actually needs filter values, instead of always - that could improve server performance
        await GetTeamOptions();
        await GetNameOptions();
    }

    public class Employee
    {
        public int EmployeeId { get; set; }
        public string Name { get; set; }
        public string Team { get; set; }
        public bool IsOnLeave { get; set; }
    }

    // in this sample we use simplified models to fetch less data from the service
    // instead of using the full Employee model that has many fields we do not need for the filters

    public class TeamNameFilterOption
    {
        public string Team { get; set; }
    }

    public class NameFilterOption
    {
        public string Name { get; set; }
    }
}

Unplanned
Last Updated: 26 Jun 2025 07:19 by Andrea
There is an order to the grouping level - field1, field2 and so on - I would like that current index in that order exposed by the grouping templates so I can know in which position they are and whether/how far they are nested.
Unplanned
Last Updated: 24 Apr 2025 05:25 by ADMIN
I would like to click on the grouping row and expand the Group. 
Unplanned
Last Updated: 19 May 2022 15:22 by Thomas

Currently, the validation of the grid can be disabled altogether via the GridValidationSettings.Enabled option. However, we cannot control the validation of the grid per column.

Also, we cannot control when the validation is triggered. The simple inputs expose the ValidateOn option, but it cannot be set to the default editors of the grid without the need for an explicit declaration of a custom editor.

Unplanned
Last Updated: 15 Mar 2023 11:53 by Jakub
Expose a parameter that allows changing the default behavior of the CheckboxList filters. Currently, all distinct options are included in the CheckBoxList. It would be useful if we can configure this and make the filters cascade like in an excel table.
Unplanned
Last Updated: 18 Oct 2023 10:50 by Craig
Created by: Craig
Comments: 0
Category: Grid
Type: Feature Request
8

I would like to lock a column at a certain index in the Grid. For example, I would like to have a column on index 0 (the first column in the Grid) and it should not be reordered by any user interaction (dragging the column itself or dragging other columns in its place). 

Also if the user tries to drag a column over my locked column the drag handlers must not be present/or show that it is an invalid drop location.

===

Telerik edit:

In the meantime, a possible workaround is to:

  1. Handle the Grid OnStateChanged event.
  2. Check if args.PropertyName is equal to "ColumnStates".
  3. Check if the Index of the first Grid column (args.GridState.ColumnStates.First()) is greater than zero.
  4. Reset at least 2 column indexes, according to your preferences, so that the first column in the Grid markup is also the first column in the UI.
  5. Reset the Grid state with SetStateAsync().

 

<p>The <strong>Name</strong> column index will always be 0.
    The Grid will either move the reordered column to index 1, or put it back to its previous index (revert).</p>

<p><label><TelerikCheckBox @bind-Value="@ShouldRevertGridColumnOrder" /> Revert Invalid Column Reordering</label></p>

<TelerikGrid @ref="@GridRef"
             Data="@GridData"
             TItem="@SampleModel"
             Pageable="true"
             Sortable="true"
             Reorderable="true"
             OnStateChanged="@OnGridStateChanged">
    <GridColumns>
        <GridColumn Field="@nameof(SampleModel.Name)" Reorderable="false" />
        <GridColumn Field="@nameof(SampleModel.GroupName)" />
        <GridColumn Field="@nameof(SampleModel.Price)" />
        <GridColumn Field="@nameof(SampleModel.Quantity)" />
        <GridColumn Field="@nameof(SampleModel.StartDate)" />
        <GridColumn Field="@nameof(SampleModel.IsActive)" />
    </GridColumns>
</TelerikGrid>

@code {
    private TelerikGrid<SampleModel>? GridRef { get; set; }

    private List<SampleModel> GridData { get; set; } = new();

    private bool ShouldRevertGridColumnOrder { get; set; }

    private IEnumerable<int>? CachedGridColumnIndexes { get; set; }

    private async Task OnGridStateChanged(GridStateEventArgs<SampleModel> args)
    {
        if (args.PropertyName == "ColumnStates")
        {
            if (args.GridState.ColumnStates.First().Index > 0 && GridRef != null)
            {
                if (ShouldRevertGridColumnOrder)
                {
                    await RevertGridColumnOrder();
                }
                else
                {
                    args.GridState.ColumnStates.First(x => x.Index == 0).Index = 1;

                    args.GridState.ColumnStates.First().Index = 0;

                    await GridRef.SetStateAsync(args.GridState);
                }
            }

            CacheGridColumnOrder();
        }
    }

    private void CacheGridColumnOrder()
    {
        var gridColumnState = GridRef?.GetState().ColumnStates;

        if (gridColumnState != null)
        {
            CachedGridColumnIndexes = gridColumnState.Select(x => x.Index);
        }
    }

    private async Task RevertGridColumnOrder()
    {
        var gridState = GridRef?.GetState();

        if (gridState != null && CachedGridColumnIndexes != null)
        {
            for (int i = 0; i < gridState.ColumnStates.Count; i++)
            {
                gridState.ColumnStates.ElementAt(i).Index = CachedGridColumnIndexes.ElementAt(i);
            }

            await GridRef!.SetStateAsync(gridState);
        }
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            CacheGridColumnOrder();
        }

        base.OnAfterRender(firstRender);
    }

    protected override void OnInitialized()
    {
        var rnd = new Random();

        for (int i = 1; i <= 7; i++)
        {
            GridData.Add(new SampleModel()
            {
                Id = i,
                Name = $"Name {i}",
                GroupName = $"Group {i % 3 + 1}",
                Price = rnd.Next(1, 100) * 1.23m,
                Quantity = rnd.Next(0, 1000),
                StartDate = DateTime.Now.AddDays(-rnd.Next(60, 1000)),
                IsActive = i % 4 > 0
            });
        }
    }

    public class SampleModel
    {
        public int Id { get; set; }
        public string Name { get; set; } = string.Empty;
        public string GroupName { get; set; } = string.Empty;
        public decimal Price { get; set; }
        public int Quantity { get; set; }
        public DateTime StartDate { get; set; }
        public bool IsActive { get; set; }
    }
}