From 5be510b6c00ea9e9f053374b3de0fcaa12728a51 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:15:12 +0200 Subject: [PATCH] kb(grid): Revamp KB for column header alignment in hierarchy (#1970) Co-authored-by: Dimo Dimov <961014+dimodi@users.noreply.github.com> --- .../grid-align-columns-hierarchy.md | 254 ++++++++++-------- .../grid-align-hierarchical-columns.png | Bin 19179 -> 0 bytes 2 files changed, 141 insertions(+), 113 deletions(-) delete mode 100644 knowledge-base/images/grid-align-hierarchical-columns.png diff --git a/knowledge-base/grid-align-columns-hierarchy.md b/knowledge-base/grid-align-columns-hierarchy.md index 8da95757e..0e726ea63 100644 --- a/knowledge-base/grid-align-columns-hierarchy.md +++ b/knowledge-base/grid-align-columns-hierarchy.md @@ -1,172 +1,200 @@ --- -title: Align Columns in Hierarchical Grid -description: How to align columns in nested detail template of a hierarchical grid. +title: Align Column Headers in Grid Hierarchy +description: How to align column headers in the nested detail template of a hierarchy Grid. type: how-to -page_title: Align Columns in Hierarchical Grid +page_title: How to Align Columns Headers at Different Grid Hierarchy Levels slug: grid-kb-align-columns-hierarchy position: tags: -ticketid: 1468988 +ticketid: 1468988, 1522877, 1644195 res_type: kb --- ## Environment + - - - - - - + + + + + +
ProductGrid for Blazor
ProductGrid for Blazor
- ## Description -I want to showcase hierarchical data in the grid and to make the DetailTemplate columns match the main column headers. -## Solution -While generally a task for a treelist type of component, you can show self-referencing data in a grid through its detail templates and if the field names match, you can even use the only the headers from the main grid. +This KB article answers the following questions: -To align the columns of nested grid detail templates, you need to: +* How to configure a hierarchy Grid and make the `DetailTemplate` Grid column headers align with the master Grid column headers? +* How to define the detail Grid columns, so that they match the master Grid columns? +* How to align the column borders of nested child Grids with the column borders of the parent Grid? + +## Solution -* set a width to the grid that matches the width of its columns -* set width to the columns of the nested grids that match the column widths of the main grid - * the first column of each child grid must have width smaller than the first column of the main grid with the size of the hierarchy expand column times the levels of hierarchy that you have -* add styles that remove the scrollbars from the grid to clean out the UI and reduce distortions that they can cause -* optionally, hide the headers of the nested grids +The best reason to align Grid column headers across hierarchy levels is when the Grid displays a self-referencing hierarchy. There are two ways to achieve the desired appearance and aligned columns: ->caption The result from the code snippet below +* Use a [TreeList component]({%slug treelist-overview%}). It may be a better option than the Grid, because the TreeList supports a random number of hierarchy levels and there is no need to define and configure each level separately. The TreeList uses the same column and column header for each data item property at any level. +* Use a Grid with [additional CSS code]({%slug themes-override%}) to align the columns at all hierarchy levels. -![Align Hierarchical Grid Columns](images/grid-align-hierarchical-columns.png) +The steps below describe how to align columns when using a Grid hierarchy. +1. Set a [custom CSS `Class`]({%slug grid-overview%}#grid-parameters) to the master (parent) Grid, so that the custom styles do not affect other Grid instances. +1. Use the custom CSS class to: + 1. Remove the padding of the `DetailTemplate` container (`td.k-detail-cell`). + 1. Disable the vertical scrollbar of the Grid data area (`div.k-grid-content`). + 1. Remove the empty space in the Grid header area, which is above the vertical scrollbar (`div.k-grid-header`). + 1. Remove the right border of the detail Grids (`.k-grid`). +1. Set the same column `Width` to the columns from all hierarchy levels, that should align with one another. +1. Set widths to all columns, except the first one of each Grid. This will allow the first column to expand and collapse automatically, depending on the hierarchy level and the available space. +1. If the number of hierarchy levels is greater than two, use [named `context` variables for the Grid `DetailTemplate`]({%slug nest-renderfragment%}). +1. (optional) Remove the header area of the detail Grids. This makes sense only if the detail Grids have no enabled features that rely on column headers, for example, sorting or filtering. >caption Align the columns in hierarchical grids ````CSHTML -@* Three levels of grids - note how the first columns of the nested grids have the width of the detail expand cell subtracted twice - for the Default Theme, it is 2*32px but that can vary between themes and based on the font-size of the page. - Also, the main grid has a width that matches closely the sum of the column widths and the horizontal scrollbars - are hidden in order to produce cleaner UX *@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - @{ - var currGridData = GetLevelData(firstLevelItem.Id); - - - - - - - - @{ - var currGridData = GetLevelData(secondLevelItem.Id); - - - - - - - - } - - +@if (HideDetailHeaders) +{ + +} @code { - List MainLevelsData { get; set; } - List AllData { get; set; } + private List GridData { get; set; } = new(); + + private bool HideDetailHeaders { get; set; } - public class SelfReferencingHierarchyModel + private void OnGridStateInit(GridStateEventArgs args) { - public int Id { get; set; } - public int? ParentId { get; set; } - public string Field1 { get; set; } - public string Field2 { get; set; } + // Expand the master Grid rows automatically + args.GridState.ExpandedItems = GridData.Where(x => x.ParentId == null).ToList(); } protected override void OnInitialized() { - AllData = new List(); + GridData = LoadFlat(); + + base.OnInitialized(); + } + + #region Grid Data Generation + + private const int TreeLevels = 3; + private int RootItems { get; set; } = 2; + private int ItemsPerLevel { get; set; } = 2; + private int IdCounter { get; set; } = 1; + + private List LoadFlat() + { + List items = new List(); - //generate top level items - for (int i = 0; i < 35; i++) + PopulateChildren(items, null, 1); + + return items; + } + + private void PopulateChildren(List items, int? parentId, int level) + { + var itemCount = level == 1 ? RootItems : ItemsPerLevel; + for (int i = 1; i <= itemCount; i++) { - AllData.Add(new SelfReferencingHierarchyModel + var itemId = IdCounter++; + items.Add(new GridItem() { - Id = i, - Field1 = $"main level {i}", - Field2 = $"main level field 2 - {i}" + Id = itemId, + ParentId = parentId, + Text = $"Level {level} Item {i}", + Quantity = Random.Shared.Next(0, 1000), + Date = new DateTime(Random.Shared.Next(2000, 2030), Random.Shared.Next(1, 13), Random.Shared.Next(1, 29)) }); - for (int j = 0; j < 12; j++) + if (level < TreeLevels) { - //generate first level items - note the Id and ParentId logic - AllData.Add(new SelfReferencingHierarchyModel - { - Id = 100 + j, - ParentId = i, - Field1 = $"first level {j}", - Field2 = $"first level field 2 - {j}" - }); - - for (int k = 0; k < 12; k++) - { - //generate second level items - note the Id and ParentId logic - AllData.Add(new SelfReferencingHierarchyModel - { - Id = 6000 * j + k, // does not really produce unique IDs here, but for this sample it does not matter - ParentId = 100 + j, - Field1 = $"second level {j}", - Field2 = $"second level field 2 - {j}" - }); - } + PopulateChildren(items, itemId, level + 1); } } - - MainLevelsData = AllData.Where(itm => itm.ParentId == null).ToList(); } - List GetLevelData(int parentId) + #endregion Grid Data Generation + + public class GridItem { - return AllData.Where(itm => itm.ParentId == parentId).ToList(); + public int Id { get; set; } + public int? ParentId { get; set; } + public string Text { get; set; } = string.Empty; + public int Quantity { get; set; } + public DateTime Date { get; set; } } } ```` +## See Also - +* [Grid Hierarchy]({%slug components/grid/features/hierarchy%}) +* [Using custom CSS with Telerik Blazor components]({%slug themes-override%}) +* [TreeList component documentation]({%slug treelist-overview%}) diff --git a/knowledge-base/images/grid-align-hierarchical-columns.png b/knowledge-base/images/grid-align-hierarchical-columns.png deleted file mode 100644 index efd7486ba55e3ec300a2937680612b7b9d3008d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19179 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 ac5snt3kRRF6X(2ps+E?I7q1l65BNV!;pXQ6