Perform column chooser for multiple grid

Hi, I want to know how can I perform the column chooser but when y choose some columns these changes should also be applied to other grids. I am working with detail templates rendering a grid in detail template so If I choose a grid (that's part of the detail template )column should change in the other grids that are rendered in the other rows of detail templates 
In this documentation example you see in detail templates of each row a grid if I change the column chooser of one of them should be applied to all the grids that are rendered in detail template. It is because the choice selection should persist in a database or local storage.

8 Replies 1 reply marked as answer

RN Rahul Narayanasamy Syncfusion Team March 18, 2021 12:56 PM UTC

Hi Adriana, 

Greetings from Syncfusion. 

Query: Perform column chooser for multiple grid - when y choose some columns these changes should also be applied to other grids(Detail grid’s),  

We have validated your query and you want to choose column from one of the Detail Grid and the chosen columns will be applied to all other detail Grid’s. You can achieve this requirement by using EnablePersistance feature. 

Reference

While enabling persistence, the state will be persisted based on ID property. So, it is recommended to explicitly set the ID property for Grid. 

We suggest you to set the ID property to Detail Grid and enable persistence property in detail Grid.  

Steps

  • Render Grid with the above mentioned properties(Set ID for detail Grid’s and enable persistence property).
  • Open any one child grid(Detail Grid), and choose required columns using column chooser.
  • Then we suggest you to save the detail Grid state manually using button click. Here, we have save the state using button click(Set State).
  • Then open the other detail Grids. Now all other detail Grids are shown with the previously chosen columns.

Find the below code snippets and sample for your reference. 

 
 
<SfButton OnClick="SetState">Set State</SfButton>    //set the state 
<SfButton OnClick="ResetState">Reset State</SfButton>    //reset the state 
 
<SfGrid ID="ParentGrid" DataSource="@Employees" Height="705px"> 
    <GridTemplates> 
        <DetailTemplate> 
            @{ 
                var employee = (context as EmployeeData); 
                <SfGrid ID="DetailGrid" @ref="DetailGridRef" DataSource="@Orders" Query="@(new Query().Where("EmployeeID", "equal", employee.EmployeeID))" 
                        ShowColumnChooser="true" Toolbar=@ToolbarItems 
                        EnablePersistence="true"> 
                    <GridColumns> 
                        . . . 
                    </GridColumns> 
                </SfGrid> 
            } 
        </DetailTemplate> 
    </GridTemplates> 
    <GridColumns> 
        . . . 
    </GridColumns> 
</SfGrid> 
 
@code{ 
    SfGrid<Order> DetailGridRef;   //Grid reference  
    public string _state;     //for maintaining grid state 
 
    . . . 
    public async Task SetState() 
    { 
        await DetailGridRef.SetPersistData(_state);   //set state using SetPersistData method 
    } 
    public async Task ResetState() 
    { 
        await DetailGridRef.ResetPersistData();    //reset the state 
    } 
} 



Note: While choosing columns using column chooser in detail Grid, we suggest you to close all the detail Grids and open only one detail Grid at that time. 

Please let us know if you have any concerns. 

Regards, 
Rahul 


Marked as answer

AS Adriana Selena Tito Ilasaca March 19, 2021 01:59 AM UTC

Hi! Thanks for the answer, it works! Just a question, talking about that only one detail should be opened I am working in the following way.
It does not matter if there is more than one detail expanded, once you open the column chooser and click ok in the column chooser, I am using the event OnActionComplete, this first collapses all the detail with detailCollapseAll and later I setPersistData. 
What I want is yes collapse all but no the detail where I opened the Column Chooser, I tried to find in args of BeforeOpenColumChoser info of the row where the column chooser was opened to keep it expanded. Is there any way to perform that ?


RN Rahul Narayanasamy Syncfusion Team March 19, 2021 01:27 PM UTC

Hi Adriana, 

Thanks for the update. 

Query: What I want is yes collapse all but no the detail where I opened the Column Chooser, I tried to find in args of BeforeOpenColumChoser info of the row where the column chooser was opened to keep it expanded. Is there any way to perform that ? 

We have validated your query and we suspect that you want to keep the detail row open in which the column chooser is opened(detail Grid where we choose columns). Here, we have prepared a sample based on your requirement. 

We have set the Detail Grid reference dynamically while opening the detail grid using DetailDataBound event. We have stored detail Grid column state in OnActionComplete event and reopened the detail Grid. 

 
 
<SfGrid ID="ParentGrid" @ref="ParentRef" DataSource="@Employees" Height="705px"> 
    <GridEvents DetailDataBound="DetailDataBoundHandler" TValue="EmployeeData"></GridEvents> 
    <GridTemplates> 
        <DetailTemplate> 
            @{ 
                var employee = (context as EmployeeData); 
                <SfGrid ID="DetailGrid" @ref="myComponents[id]" DataSource="@Orders" Query="@(new Query().Where("EmployeeID", "equal", employee.EmployeeID))" 
                        ShowColumnChooser="true" Toolbar=@ToolbarItems 
                        EnablePersistence="true"> 
                    <GridEvents OnActionComplete="ActionCompletedHandler"  BeforeOpenColumnChooser="BeforeOpenColumnChooserHandler" TValue="Order"></GridEvents> 
                    <GridColumns> 
                        . . . 
                    </GridColumns> 
                </SfGrid> 
            } 
        </DetailTemplate> 
    </GridTemplates> 
    <GridColumns> 
        . . . 
    </GridColumns> 
</SfGrid> 
 
@code{ 
    SfGrid<EmployeeData> ParentRef { get; set; }    //parent Grid reference 
    public string _state; 
 
    public string id { get; set; } 
    private Dictionary<string, SfGrid<Order>> myComponents = new Dictionary<string, SfGrid<Order>>();  //for storing Detail Grid  reference dynamically 
    public int? CId { get; set; } 
 
 
    . . . 
 
 
    public void BeforeOpenColumnChooserHandler(ColumnChooserEventArgs Args) 
    { 
        CId = int.Parse(this.id);     //get id while opening column chooser, using this id we have reopened the detail Grid 
    } 
    public void DetailDataBoundHandler(DetailDataBoundEventArgs<EmployeeData> args) 
    { 
        id = args.Data.EmployeeID.ToString();     //set detail Grid id when opening detail Grid 
    } 
    public async Task ActionCompletedHandler(ActionEventArgs<Order> args) 
    { 
        if (args.RequestType.Equals(Syncfusion.Blazor.Grids.Action.ColumnState)) 
        { 
            var RowVal = Employees.Where(or => or.EmployeeID == CId).FirstOrDefault();    //from the id from column chooser, we have filtered the parent data 
            await myComponents[CId.ToString()].SetPersistData(_state);   //persist state in corresponding detail grid reference 
            await ParentRef.DetailCollapseAll();    //collapse all detail grid's using parent grid reference 
            await ParentRef.DetailExpandCollapseRow(RowVal);     //expand the previously opened column chooser detail Grid 
        } 
    } 
 
} 


Reference

Please let us know if you have any concerns. 

Regards, 
Rahul 



AS Adriana Selena Tito Ilasaca March 19, 2021 08:03 PM UTC

Thanks for the answer, apparently is working but it is saving the last expanded row, if I expand row one, row two, row three in that order but I decide to open the column chooser of the second row, all will be closed but not the last displayed.
To avoid it I decided to use the custom Toolbar have and open the column chooser of detailed grids from the parent grid, But I saw the column chooser is not opened if no detail rows are expanded. I can enable this toolbar item if at least one detail is expanded this can be done in DetailDatabound but what happens if I decide to collapse the details one by one, Is there any event to trigger when the detail grid is collapsed?
I need to enable the toolbar column child button if at least one detail row is displayed but disable it if all details are not displayed. 
Attaching a demo project and a gif

1. As you can see in the gif the column Child is only enabling when a row is expanded. I am validating this with a list. I should Remove the item of a list when a row is collapsed.

Attachment: GridDetailTemplate_74d4a552.rar


AS Adriana Selena Tito Ilasaca March 24, 2021 02:31 PM UTC

Hi there, any update about this? 
Is there any way to know when a detailed template is collapsed?
I will appreciate your answer



RN Rahul Narayanasamy Syncfusion Team March 25, 2021 03:28 PM UTC

Hi Adriana, 

We are sorry for the inconvenience and delay in get back to you. 

For this requirement(choose columns from one of the Detail Grid and the chosen columns will be applied to all other detail Grid’s), we suggest you to achieve your requirement by using below way(using Visible property of Column and ActionEvents)  instead of using EnablePersistance feature.  

Here, we have set Visibility values in Dictionary object at initial rendering. Based on this dictionary object value, the detail Grid columns will be shown at initial. While choosing columns in one of the detail Grid, we have updated the Visible property value in OnActionBegin event of the Grid. Now you can able to choose columns from any detail Grids and it will be applied to all detail Grids without any issues. 

Also, you want to keep open the detail Grid which the column chooser is opened(detail Grid where we choose columns). For this, we have set a property(unique value corresponding to detail grid row value) using attributes property. While clicking the detail Grid toolbar(column chooser), we make a interop call using IJSRuntime and get the unique id(which Grid column chooser is clicked) and opened the detail Grid. 

Refer the below code snippets and sample for your reference. 

[Index.js] 
@using Syncfusion.Blazor.Grids 
@using Syncfusion.Blazor.Data 
@using Syncfusion.Blazor.Buttons 
@using Syncfusion.Blazor.Navigations 
@inject IJSRuntime JSRuntime 
 
 
<SfGrid ID="ParentGrid" @ref="ParentRef" DataSource="@Employees" Height="705px"> 
    <GridEvents DetailDataBound="DetailDataBoundHandler" TValue="EmployeeData"></GridEvents> 
    <GridTemplates> 
        <DetailTemplate> 
            @{ 
                var employee = (context as EmployeeData); 
                <SfGrid @ref="myComponents[id]" @attributes="@(new Dictionary<string, object>(){ { "something", @employee.EmployeeID }})" 
                        DataSource="@Orders" Query="@(new Query().Where("EmployeeID", "equal", employee.EmployeeID))" 
                        Toolbar=@ToolbarItems ShowColumnChooser="true"> 
                    <GridEvents OnActionBegin="Begin" OnActionComplete="ActionCompletedHandler" 
                                OnToolbarClick="ToolbarClickHandler" TValue="Order"></GridEvents> 
                    <GridColumns> 
                        <GridColumn Field=@nameof(Order.OrderID) HeaderText="OrderID" Visible="@Fields["OrderID"]" Width="110"> </GridColumn> 
                        <GridColumn Field=@nameof(Order.CustomerName) HeaderText="CustomerName" Visible="@Fields["CustomerName"]" Width="110"></GridColumn> 
                        <GridColumn Field=@nameof(Order.ShipCountry) HeaderText="ShipCountry" Visible="@Fields["ShipCountry"]" Width="110"></GridColumn> 
                    </GridColumns> 
                </SfGrid> 
            } 
        </DetailTemplate> 
    </GridTemplates> 
    <GridColumns> 
        . ..  
    </GridColumns> 
</SfGrid> 
 
@code{ 
    SfGrid<EmployeeData> ParentRef { get; set; }    //parent Grid reference 
    IDictionary<string, bool> Fields = new Dictionary<string, bool>();  //for storing the Visibility value  
 
    public string id { get; set; } 
    private Dictionary<string, SfGrid<Order>> myComponents = new Dictionary<string, SfGrid<Order>>();  //for storing Detail Grid  reference dynamically 
                                                                                                       //public int? CId { get; set; } 
    string ColChoosenID { get; set; } 
 
 
    public string[] ToolbarItems = new string[] { "ColumnChooser" }; 
 
    protected override void OnInitialized() 
    { 
        Fields.Add("OrderID", true); 
        Fields.Add("CustomerName", false); 
        Fields.Add("ShipCountry", true);   //stored Visibility value at initial  
    } 
    . . . 
 
    public async Task Begin(ActionEventArgs<Order> args) 
    { 
        if (args.RequestType.Equals(Syncfusion.Blazor.Grids.Action.ColumnState))   //checking requesttype 
        { 
            var hiddenCount = args.HiddenColumns.Count();    //get hidden columns count 
            var visibleCount = args.VisibleColumns.Count();  //get visible columns count 
            var totCount = Fields.Count(); 
            for (var i = 0; i < hiddenCount; i++) 
            { 
                Fields[args.HiddenColumns[i].Field] = args.HiddenColumns[i].Visible;     //setting Visibility values in Dictionary object 
            } 
            for (var i = 0; i < visibleCount; i++) 
            { 
                Fields[args.VisibleColumns[i].Field] = args.VisibleColumns[i].Visible;  //setting Visibility values in Dictionary object 
            } 
        } 
    } 
 
    public void DetailDataBoundHandler(DetailDataBoundEventArgs<EmployeeData> args) 
    { 
        id = args.Data.EmployeeID.ToString();     //set detail Grid id when opening detail Grid 
    } 
    public async Task ActionCompletedHandler(ActionEventArgs<Order> args) 
    { 
        if (args.RequestType.Equals(Syncfusion.Blazor.Grids.Action.ColumnState)) 
        { 
            var RowVal = Employees.Where(or => or.EmployeeID == int.Parse(ColChoosenID)).FirstOrDefault(); 
            await ParentRef.DetailCollapseAll();    //collapse all detail grid's using parent grid reference 
            await ParentRef.DetailExpandCollapseRow(RowVal);     //expand the previously opened column chooser detail Grid 
        } 
    } 
    public async Task ToolbarClickHandler(Syncfusion.Blazor.Navigations.ClickEventArgs args) 
    { 
        string[] words = args.Item.Id.Split('_');   //get detail grid id 
        ColChoosenID = await JSRuntime.InvokeAsync<string>("getValue", words[0]);   //make a interop call using detail grid id 
    } 
} 
[Interop.js] 
function getValue(id) { 
    var uniqueValueDetailGrid = document.getElementById(id).getAttribute("something");    
    return uniqueValueDetailGrid;   //return id 
} 
<head> 
    . . . 
    <link rel='nofollow' href="_content/Syncfusion.Blazor/styles/fabric.css" rel="stylesheet" /> 
    <script src="~/Interop.js"></script> 
</head> 


Please let us know if you have any concerns. 

Regards, 
Rahul 



AS Adriana Selena Tito Ilasaca March 25, 2021 04:11 PM UTC

Thanks for your answer.
But as I mention before, we need to persist the changes of column chooser, and I see in the OnInitialized life cycle method we set the values for the visibility of columns and I understand because we need to fill the dictionary. 
but I think it is not correct and it won't be possible to fill the dictionary with the saved state in local storage. 


RN Rahul Narayanasamy Syncfusion Team March 26, 2021 02:12 PM UTC

Hi Adriana, 

Thanks for the update. 
 
Query: But as I mention before, we need to persist the changes of column chooser, I think it is not correct and it won't be possible to fill the dictionary with the saved state in local storage. 

We have validated your query and we have modified the sample based on your requirement. Here, we have handled the state persistence manually for achieving this requirement. We have store the detail Grid state in browser local storage by using interop call instead of using dictionary object at initialization and Visible property. While choosing columns in detail Grid, we have get the detail Grid state(get persist data using GetPersistData method. For setting used SetPersistData)  and sent to interop function for saving the state in browser local storage.  

In interop file, we have set/get the Grid state in browser local storage using setItem/setItem method in the window.localStorage. We have reset the previous state in detail Grid while opening the detail Grid using DetailDataBound event. Find the below code snippets and sample for your reference. 

 
. . . 
@inject IJSRuntime JSRuntime 
 
 
<SfGrid ID="ParentGrid" @ref="ParentRef" DataSource="@Employees" Height="705px"> 
    <GridEvents DetailDataBound="DetailDataBoundHandler" TValue="EmployeeData"></GridEvents> 
    <GridTemplates> 
        <DetailTemplate> 
            @{ 
                var employee = (context as EmployeeData); 
                <SfGrid @ref="myComponents[id]" @attributes="@(new Dictionary<string, object>(){ { "something", @employee.EmployeeID }})" 
                        DataSource="@Orders" Query="@(new Query().Where("EmployeeID", "equal", employee.EmployeeID))" 
                        Toolbar=@ToolbarItems ShowColumnChooser="true"> 
                    <GridEvents OnActionComplete="ActionCompletedHandler" 
                                OnToolbarClick="ToolbarClickHandler" TValue="Order"></GridEvents> 
                    <GridColumns> 
                        . . . 
                    </GridColumns> 
                </SfGrid> 
            } 
        </DetailTemplate> 
    </GridTemplates> 
    <GridColumns> 
        . . . 
    </GridColumns> 
</SfGrid> 
 
@code{ 
    SfGrid<EmployeeData> ParentRef { get; set; }    //parent Grid reference 
    IDictionary<string, bool> Fields = new Dictionary<string, bool>();  //for storing the Visibility value  
 
    public string id { get; set; } 
    private Dictionary<string, SfGrid<Order>> myComponents = new Dictionary<string, SfGrid<Order>>();  //for storing Detail Grid  reference dynamically 
                                                                                                   
    string ColChoosenID { get; set; } 
 
    public string _state; 
 
 
    . . . 
 
    public async Task DetailDataBoundHandler(DetailDataBoundEventArgs<EmployeeData> args) 
    { 
        id = args.Data.EmployeeID.ToString();     //set detail Grid id when opening detail Grid 
        var state = await JSRuntime.InvokeAsync<string>("getStateValue");  //calling interop function for getting the state which stored in browser local storage 
        if(state != null) 
        { 
            await myComponents[id].SetPersistData(state);   //set the previous state  
        } 
    } 
    public async Task ActionCompletedHandler(ActionEventArgs<Order> args) 
    { 
        if (args.RequestType.Equals(Syncfusion.Blazor.Grids.Action.ColumnState)) 
        { 
            var RowVal = Employees.Where(or => or.EmployeeID == int.Parse(ColChoosenID)).FirstOrDefault(); 
            _state = await myComponents[ColChoosenID].GetPersistData();   //get state of the Grid  
            await JSRuntime.InvokeAsync<string>("setStateValue", _state);   //send the state to interop function for storing the state in browser local storage 
            await ParentRef.DetailCollapseAll();    //collapse all detail grid's using parent grid reference 
            await ParentRef.DetailExpandCollapseRow(RowVal);     //expand the previously opened column chooser detail Grid 
        } 
    } 
    public async Task ToolbarClickHandler(Syncfusion.Blazor.Navigations.ClickEventArgs args) 
    { 
        string[] words = args.Item.Id.Split('_'); 
        ColChoosenID = await JSRuntime.InvokeAsync<string>("getValue", words[0]);   //make a interop call using detail grid id 
    } 
} 
[Interop.js] 
function getValue(id) { 
    var uniqueValueDetailGrid = document.getElementById(id).getAttribute("something"); 
    return uniqueValueDetailGrid; 
} 
 
function setStateValue(model) { 
    //set the Grid model. 
    window.localStorage.setItem('gridGrid', JSON.stringify(model)); //"gridGrid" is some id for storing the state. 
} 
 
function getStateValue() { 
    //get the Grid model. 
    var value = window.localStorage.getItem('gridGrid'); //"gridGrid" id for getting the state which is previous stored. 
    var model = JSON.parse(value); 
    return model; 
} 


Reference

Please let us know if you have any concerns. 

Regards, 
Rahul 



Loader.
Up arrow icon