We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date

How to hide detail row

Hi,

its not mentioned how to hide/show the detail row for treegrid - we would like to achieve the same behavior as in datagrid ( but with hierarchical data - thats why we use treegrid instead of datagrid )


6 Replies 1 reply marked as answer

CH Christoph December 22, 2022 08:22 AM UTC

we have a workaround for selection based hide/show but we need a state that is independend from selection
#table-id .e-detailrow {
    display: none;
}
#table-id .e-row[aria-selected="true"] + .e-detailrow {
    display: table-row;
}

edit: moved drag&drop problems to bug report ticket



FS Farveen Sulthana Thameeztheen Basha Syncfusion Team December 22, 2022 03:50 PM UTC


Hi Christoph,


Before proceeding this, we need some more additional details about the requirement. Share us the following details.


  1. Do you want to hide the Detail row at Initial rendering?
  2. Screenshot/Video Demo about your requirement.
  3. By using the Selection CSS(How you have hide/show the Detail row). Share video demo of it. We are unable to hide/show from applying the CSS
  4. Exact scenario you need to achieve.(Explain in detail)


Regards,

Farveen sulthana T



CH Christoph December 22, 2022 04:19 PM UTC

  1. yes - this should be the default
  2. exactly like in Detail Row DataGrid ( detail toggle state for each row, possible to view multiple detail rows at same time )
  3. see attachment ( apply_css_detail_row_toggle.zip )
  4. "In the hierarchical device list, the user can display a device overview (with all properties, statistics and interactions) for each device. Several device overviews can be displayed at the same time."

Overall, we need the same behaviour of "DataGrid Detail for TreeGrid

Attachment: apply_css_detail_row_toggle_7410783a.zip


FS Farveen Sulthana Thameeztheen Basha Syncfusion Team December 26, 2022 07:33 AM UTC

Hi Christoph,


Further analyzing, we couldn’t achieve the exact functionality that Grid component possess. By default TreeGrid display the detail Template in Expanded state only. So it is not feasible to show/hide detail Template for specific row.


As a workaround, we have implemented a solution using Microsoft JsInterop and which allows to show the detail row using external CSS with Expanding Event of the TreeGrid. Initially we can render the TreeGrid by setting EnableCollapseAll property and hide the Detailrow by setting display:none property. Based on this you can handle your own customization as per your convenience.


Refer to the code below:-

@inject IJSRuntime JSRuntime

 

<SfTreeGrid @ref="@reference"  TValue="SelfReferenceData" DataSource="@TreeData" Height="400" EnableCollapseAll="true" IdMapping="TaskId" ParentIdMapping="ParentId"

            TreeColumnIndex="1">

  TreeGridEvents Expanding="ExpandingHandler" Collapsing="CollapsingHandler" TValue="Employee"></TreeGridEvents>     

   

            .   .    .

</SfTreeGrid>

 

@code{

    private IEnumerable<Employee> TreeGridData { get; set; }

    protected override void OnInitialized()

    {

        this.TreeGridData = Employee.GetTemplateData();

    }

    public async Task  ExpandingHandler(RowExpandingEventArgs<Employee> args)

    {

        // Here you can customize your code

         await JSRuntime.InvokeAsync<object>("TreeGridfile");

    }

}

 

TreeGridfile.js

function TreeGridfile() {

    var rows = document.getElementById("TreeGrid").querySelectorAll(".e-detailrow");

    Array.from(rows).map((row) => {

        row.classList.add('newrow');       //add class for display detailrow

    });

}

 

<style>

.e-detailrow {

    display: none;      //hide detailrow Initially

}

.newrow {

  display: table-row;   //show detailrow  

}

</style>

_Layout.cshtml:-

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="utf-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>ServerApp</title>

    <base rel='nofollow' href="~/" />

    <link rel="stylesheet" rel='nofollow' href="css/bootstrap/bootstrap.min.css" />

       .   .   .

    <script src="~/TreeGridfile.js"></script>

</head>

 



CH Christoph January 9, 2023 08:19 AM UTC

Hi,

thanks for your provided approach.

Unfortunately, this one does not fully meet our requirements, so we chosed to DataGrid as base and implement the hierarchy handling by ourself.


for anyone who is facing same problem, here is our approach:


GridHierarchy.razor.cs

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Logging;
using Microsoft.JSInterop;
using Syncfusion.Blazor.Grids;
using Action = Syncfusion.Blazor.Grids.Action;


internal class HierarchyState
{
public int Level { get; set; }
public bool Expanded { get; set; }


public bool IsVisible()
{
if( Parent == null )
{
return true;
}


if( Expanded == false )
{
return false;
}


return Parent.IsVisible();
}


public HierarchyState? Parent { get; set; }
}


/**
* Require to sort data before set to DataSource ( with "Sorting" )
* events are auto registered if not used - otherwise call function by yourself
* OnActionDone - on RequestType == Refresh, call Update
* OnActionStart - on RequestType == Refresh, set PreventRender true
*/
public partial class GridHierarchy : OwningComponentBase
{
[CascadingParameter]
protected SfGrid Parent { get; set; } = null!;


[Parameter, EditorRequired]
public Func GetParentId { get; set; } = null!;


[Parameter, EditorRequired]
public Func GetId { get; set; } = null!;


[Inject]
private IJSRuntime _js { get; set; } = null!;


public int MaxLevel { get; private set; }


private IReadOnlyDictionary _hierarchyLevels = ImmutableDictionary.Empty;


protected override async Task OnAfterRenderAsync( bool firstRender )
{
await base.OnAfterRenderAsync( firstRender );


if( firstRender )
{
Register();
}
}


private void Register()
{
if( Parent.GridEvents == null )
{
Parent.GridEvents = new GridEvents();
}


if( !Parent.GridEvents.OnActionBegin.HasDelegate )
{
Parent.GridEvents.OnActionBegin = new EventCallback>( this, OnActionStart );
}


if( !Parent.GridEvents.OnActionComplete.HasDelegate )
{
Parent.GridEvents.OnActionComplete = new EventCallback>( this, OnActionDone );
}
}


private void OnActionStart( ActionEventArgs args )
{
if( args.RequestType == Action.Refresh )
{
args.PreventRender = true;
}
}


private Task OnActionDone( ActionEventArgs args )
{
if( args.RequestType == Action.Refresh )
{
return Update().AsTask();
}


return Task.CompletedTask;
}


public int GetLevel( TValue entry )
{
if( !_hierarchyLevels.TryGetValue( GetParentId.Invoke( entry ), out HierarchyState? state ) )
{
return -1;
}


return state.Level;
}


/**
* -1 => has no children
* 0 => collapsed
* 1 => expanded
*/
public int GetExpandState( TValue entry )
{
if( !_hierarchyLevels.TryGetValue( GetId.Invoke( entry ), out HierarchyState? state ) )
{
return -1;
}


return state.Expanded ? 1 : 0;
}


public ValueTask ToggleLevel( TKey id )
{
if( !_hierarchyLevels.TryGetValue( id, out HierarchyState? state ) )
{
return ValueTask.CompletedTask;
}


state.Expanded = !state.Expanded;


return Update();
}


public ValueTask Update()
{
// create visible list
List visibleRows = new();


int index = 0;
foreach( TValue entry in Parent.DataSource )
{
int currentIndex = index++;


if( !_hierarchyLevels.TryGetValue( GetParentId.Invoke( entry ), out HierarchyState? state ) )
{
continue;
}


if( !state.IsVisible() )
{
continue;
}


visibleRows.Add( currentIndex );
}


return _js.InvokeVoidAsync( "GridHierarchy_UpdateRowVisibility", Parent.ID, visibleRows );
}


public IReadOnlyList Sorting( IReadOnlyList data, TKey empty )
{
if( data.Count == 0 )
{
return data;
}


Dictionary> levelData = data
.GroupBy( GetParentId.Invoke )
.ToDictionary( entry => entry.Key, entry => entry.ToList() );


List orderedData = new( data.Count );


if( !levelData.TryGetValue( empty, out List? firstLevelData ) )
{
return data;
}


Dictionary hierarchyData = new( levelData.Count );
orderedData.AddRange( firstLevelData );


void HierarchyLevelConstruction( int startIndex, int endIndex, int level, HierarchyState? parentState )
{
for( int index = endIndex; index >= startIndex; index-- )
{
TValue entry = orderedData[index];


TKey id = GetId.Invoke( entry );


if( !levelData.TryGetValue( id, out List? subLevelData ) )
{
continue;
}


int targetIndex = index + 1;
int targetLevel = level + 1;


if( targetIndex > orderedData.Count )
{
orderedData.AddRange( subLevelData );
}
else
{
orderedData.InsertRange( targetIndex, subLevelData );
}


if( !_hierarchyLevels.TryGetValue( id, out HierarchyState? state ) )
{
state = new();
}


state.Level = targetLevel;
state.Parent = parentState;


hierarchyData.Add( id, state );
if( targetLevel > MaxLevel )
{
MaxLevel = targetLevel;
}


HierarchyLevelConstruction( targetIndex, targetIndex + subLevelData.Count - 1, targetLevel, state );
}
}


if( !_hierarchyLevels.TryGetValue( empty, out HierarchyState? baseState ) )
{
baseState = new();
}
hierarchyData.Add( empty, baseState );
HierarchyLevelConstruction( 0, orderedData.Count - 1, 0, baseState );


_hierarchyLevels = hierarchyData;
return orderedData;
}
}


javascript

function GridHierarchy_UpdateRowVisibility( id, visibleRows )
{
const dataTableSelector = '#' + id + '_content_table';
const hideClass = 'd-none';


const rows = document.querySelectorAll( dataTableSelector + ' .e-row' );


rows.forEach( ( row, index ) =>
{
const visible = visibleRows.includes( index );


if( visible )
{
row.classList.remove( hideClass );
}
else
{
row.classList.add( hideClass );
}
} );
}



Marked as answer

SG Suganya Gopinath Syncfusion Team January 10, 2023 05:08 PM UTC

Hi Christoph,

Thank you for sharing the solution, it will be useful. 

Please get back to us for further assistance.



Loader.
Live Chat Icon For mobile
Up arrow icon