Column Chooser in React Treegrid component
1 Sep 202524 minutes to read
Column Chooser Template in Syncfusion React TreeGrid
The Column Chooser Template feature allows full customization of the column chooser’s header, content, and footer, making it easier to manage column visibility. To enable the column chooser, set showColumnChooser to true and add ColumnChooser to the toolbar property.
To implement a custom column chooser template in the TreeGrid, use the following properties:
-
columnChooserSettings.headerTemplate - Defines the header template of the column chooser.
-
columnChooserSettings.template- Defines the content template.
-
columnChooserSettings.footerTemplate - Defines the footer template.
In this example, a Syncfusion TreeView component is rendered inside the column chooser. To use the TreeView component, install the Syncfusion TreeView package as described in the documentation. The columnChooserSettings.template
property is used to render the TreeView component with checkboxes.Checkbox selection is handled using the nodeClicked and keyPress events, which organize columns into Order Details, Shipping Details, and Delivery Status.
The column chooser footer is customized using columnChooserSettings.footerTemplate
, replacing the default buttons with customized Apply and Close buttons. The Apply button updates column visibility based on selection, while the Close button closes the column chooser via the onClick
event. Additionally, the header is customized using columnChooserSettings.headerTemplate
to include a title and an icon.
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import { TreeGridComponent, ColumnsDirective, ColumnDirective, Page, Toolbar, ColumnChooser, ToolbarItems, Inject } from '@syncfusion/ej2-react-treegrid';
import { stackedData } from './data';
import { TreeView, TreeViewComponent } from '@syncfusion/ej2-react-navigations';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
function App() {
const toolbar = ['ColumnChooser'];
const columnChooserSettings = { template: Template, headerTemplate: HeaderTemplate, footerTemplate: FooterTemplate }
function HeaderTemplate() {
return (
<div>
<span id="column-chooser-text" style=>Column Options</span>
</div>
);
}
// Render TreeView in the column chooser's Content
function Template(props) {
const parentNodes = [
{ id: 1, name: 'Order Details', hasChild: true, expanded: true },
{ id: 2, name: 'Shipment Details', hasChild: true, expanded: true },
{ id: 3, name: 'Price Details', hasChild: true, expanded: true },
];
let treeData = [];
if (props.columns && props.columns.length) {
treeData = props.columns.map((column) => {
let parentId;
switch (column.field) {
case 'orderID':
case 'orderName':
case 'orderDate':
parentId = 1;
break;
case 'shipMentCategory':
case 'shippedDate':
case 'units':
parentId = 2;
break;
case 'unitPrice':
case 'price':
parentId = 3;
break;
default:
break;
}
return {
id: column.uid,
name: column.headerText,
pid: parentId,
isChecked: column.visible
};
});
const uniquePids = [];
treeData.forEach((item) => {
if (!uniquePids.includes(item.pid)) {
uniquePids.push(item.pid);
}
});
const filteredParents = parentNodes.filter((parent) => uniquePids.includes(parent.id));
treeData.push(...filteredParents);
} else {
treeData = [];
}
const fields = { dataSource: treeData, id: 'id', parentID: 'pid', text: 'name', hasChildren: 'hasChild' };
return (
<div>
{props.columns && props.columns.length ? (<TreeViewComponent fields={fields} cssClass="no-border" showCheckBox={true} nodeClicked={nodeCheck} keyPress={nodeCheck} ref={(treeview ) => { treeObj = treeview; }} />) : (<div className="no-record-text">No Matches Found</div>)}
</div>
);
}
function FooterTemplate() {
return (
<div id="columnChooserFooter">
<ButtonComponent onClick={columnChooserSubmit}>Apply</ButtonComponent>
<ButtonComponent onClick={columnChooserClose}>Close</ButtonComponent>
</div>
);
}
// Handle checking/unchecking nodes in the TreeView (column chooser)
function nodeCheck(args) {
let checkedNode = [args.node];
if (args.event.target.classList.contains('e-fullrow') || args.event.key == "Enter") {
let getNodeDetails = treeObj.getNode(args.node);
if (getNodeDetails.isChecked == 'true') {
treeObj.uncheckAll(checkedNode);
} else {
treeObj.checkAll(checkedNode);
}
}
}
function columnChooserClose() {
(treegridInstance.grid.columnChooserModule).hideDialog();
}
// Apply the column chooser selection
function columnChooserSubmit() {
const checkedElements = [];
const uncheckedElements = [];
var showColumns = treegridInstance.getVisibleColumns().filter(function (column) { return (column.showInColumnChooser === true); });
showColumns = showColumns.map(function (col) { return col.headerText; });
const treeItems = document.querySelectorAll('.e-list-item');
treeItems.forEach(item => {
const itemDetails = treeObj.getNode(item);
if (!itemDetails.hasChildren) {
if (item.getAttribute('aria-checked') === 'true') {
checkedElements.push(itemDetails.text);
} else {
uncheckedElements.push(itemDetails.text);
}
}
});
showColumns = showColumns.filter((col) => !uncheckedElements.includes(col));
checkedElements.forEach((item) => {
if (!showColumns.includes(item)) {
showColumns.push(item);
}
});
var columnsToUpdate = { visibleColumns: showColumns, hiddenColumns: uncheckedElements };
treegridInstance.grid.columnChooserModule.changeColumnVisibility(columnsToUpdate);
}
let treeObj;
let treegridInstance;
return (
<div className="control-pane">
<div className="control-section">
<TreeGridComponent
dataSource={stackedData}
id="TreeGrid"
ref={(treegrid ) => { treegridInstance = treegrid }}
treeColumnIndex={1}
childMapping="subtasks"
height="350"
allowPaging={true}
pageSettings=
showColumnChooser={true}
columnChooserSettings={columnChooserSettings}
toolbar={toolbar}
clipMode='EllipsisWithTooltip'
>
<ColumnsDirective>
<ColumnDirective
columns={[
{
field: "orderID",
headerText: "Order ID",
width: 90,
textAlign: "Right",
showInColumnChooser: false,
},
{
field: "orderName",
headerText: "Order Name",
width: 190,
textAlign: "Left",
},
{
field: "orderDate",
headerText: "Order Date",
width: 110,
textAlign: "Right",
format: "yMd",
},
]}
headerText="Order Details"
textAlign="Center"
></ColumnDirective>
<ColumnDirective
columns={[
{
field: "shipMentCategory",
headerText: "Shipment Category",
width: 150,
textAlign: "Left",
},
{
field: "shippedDate",
headerText: "Shipped Date",
width: 120,
textAlign: "Right",
format: "yMd",
},
{
field: "units",
headerText: "Units",
width: 80,
textAlign: "Right",
},
]}
headerText="Shipment Details"
textAlign="Center"
></ColumnDirective>
<ColumnDirective
columns={[
{
field: "unitPrice",
headerText: "Price per unit",
format: "C2",
type: "number",
textAlign: "Right",
width: 120,
},
{
field: "price",
headerText: "Total Price",
width: 115,
format: "C",
textAlign: "Right",
type: "number",
},
]}
headerText="Price Details"
textAlign="Center"
></ColumnDirective>
</ColumnsDirective>
<Inject services={[Page, Toolbar, ColumnChooser,]} />
</TreeGridComponent>
</div>
</div>
);
};
export default App;
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import { TreeGridComponent, ColumnsDirective, ColumnDirective, Page, Toolbar, ColumnChooser, ToolbarItems, Inject } from '@syncfusion/ej2-react-treegrid';
import { stackedData } from './data';
import { TreeView, TreeViewComponent } from '@syncfusion/ej2-react-navigations';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
function App() {
const toolbar: any = ['ColumnChooser'];
const columnChooserSettings: any = { template: Template, headerTemplate: HeaderTemplate, footerTemplate: FooterTemplate }
function HeaderTemplate(): any {
return (
<div>
<span id="column-chooser-text" style=>Column Options</span>
</div>
);
}
// Render TreeView in the column chooser's Content
function Template(props: any): any {
const parentNodes = [
{ id: 1, name: 'Order Details', hasChild: true, expanded: true },
{ id: 2, name: 'Shipment Details', hasChild: true, expanded: true },
{ id: 3, name: 'Price Details', hasChild: true, expanded: true },
];
let treeData: { [key: string]: Object }[] = [];
if (props.columns && props.columns.length) {
treeData = props.columns.map((column: any) => {
let parentId: any;
switch (column.field) {
case 'orderID':
case 'orderName':
case 'orderDate':
parentId = 1;
break;
case 'shipMentCategory':
case 'shippedDate':
case 'units':
parentId = 2;
break;
case 'unitPrice':
case 'price':
parentId = 3;
break;
default:
break;
}
return {
id: column.uid,
name: column.headerText,
pid: parentId,
isChecked: column.visible
};
});
const uniquePids: string[] = [];
treeData.forEach((item: any) => {
if (!uniquePids.includes(item.pid)) {
uniquePids.push(item.pid);
}
});
const filteredParents = parentNodes.filter((parent: any) => uniquePids.includes(parent.id));
treeData.push(...filteredParents);
} else {
treeData = [];
}
const fields = { dataSource: treeData, id: 'id', parentID: 'pid', text: 'name', hasChildren: 'hasChild' };
return (
<div>
{props.columns && props.columns.length ? (<TreeViewComponent fields={fields} cssClass="no-border" showCheckBox={true} nodeClicked={nodeCheck} keyPress={nodeCheck} ref={(treeview : any) => { treeObj = treeview; }} />) : (<div className="no-record-text">No Matches Found</div>)}
</div>
);
}
function FooterTemplate(): any {
return (
<div id="columnChooserFooter">
<ButtonComponent onClick={columnChooserSubmit}>Apply</ButtonComponent>
<ButtonComponent onClick={columnChooserClose}>Close</ButtonComponent>
</div>
);
}
// Handle checking/unchecking nodes in the TreeView (column chooser)
function nodeCheck(args: any): void {
let checkedNode: any = [args.node];
if (args.event.target.classList.contains('e-fullrow') || args.event.key == "Enter") {
let getNodeDetails: any = treeObj.getNode(args.node);
if (getNodeDetails.isChecked == 'true') {
treeObj.uncheckAll(checkedNode);
} else {
treeObj.checkAll(checkedNode);
}
}
}
function columnChooserClose() {
(treegridInstance.grid.columnChooserModule as any).hideDialog();
}
// Apply the column chooser selection
function columnChooserSubmit() {
const checkedElements: any = [];
const uncheckedElements: any = [];
var showColumns: any = treegridInstance.getVisibleColumns().filter(function (column: any) { return (column.showInColumnChooser === true); });
showColumns = showColumns.map(function (col: any) { return col.headerText; });
const treeItems = document.querySelectorAll('.e-list-item');
treeItems.forEach(item => {
const itemDetails = treeObj.getNode(item);
if (!itemDetails.hasChildren) {
if (item.getAttribute('aria-checked') === 'true') {
checkedElements.push(itemDetails.text);
} else {
uncheckedElements.push(itemDetails.text);
}
}
});
showColumns = showColumns.filter((col: any) => !uncheckedElements.includes(col));
checkedElements.forEach((item :any) => {
if (!showColumns.includes(item)) {
showColumns.push(item);
}
});
var columnsToUpdate: any = { visibleColumns: showColumns, hiddenColumns: uncheckedElements };
treegridInstance.grid.columnChooserModule.changeColumnVisibility(columnsToUpdate);
}
let treeObj: TreeView;
let treegridInstance: TreeGridComponent;
return (
<div className="control-pane">
<div className="control-section">
<TreeGridComponent
dataSource={stackedData}
id="TreeGrid"
ref={(treegrid :any) => { treegridInstance = treegrid }}
treeColumnIndex={1}
childMapping="subtasks"
height="350"
allowPaging={true}
pageSettings=
showColumnChooser={true}
columnChooserSettings={columnChooserSettings}
toolbar={toolbar}
clipMode='EllipsisWithTooltip'
>
<ColumnsDirective>
<ColumnDirective
columns={[
{
field: "orderID",
headerText: "Order ID",
width: 90,
textAlign: "Right",
showInColumnChooser: false,
},
{
field: "orderName",
headerText: "Order Name",
width: 190,
textAlign: "Left",
},
{
field: "orderDate",
headerText: "Order Date",
width: 110,
textAlign: "Right",
format: "yMd",
},
]}
headerText="Order Details"
textAlign="Center"
></ColumnDirective>
<ColumnDirective
columns={[
{
field: "shipMentCategory",
headerText: "Shipment Category",
width: 150,
textAlign: "Left",
},
{
field: "shippedDate",
headerText: "Shipped Date",
width: 120,
textAlign: "Right",
format: "yMd",
},
{
field: "units",
headerText: "Units",
width: 80,
textAlign: "Right",
},
]}
headerText="Shipment Details"
textAlign="Center"
></ColumnDirective>
<ColumnDirective
columns={[
{
field: "unitPrice",
headerText: "Price per unit",
format: "C2",
type: "number",
textAlign: "Right",
width: 120,
},
{
field: "price",
headerText: "Total Price",
width: 115,
format: "C",
textAlign: "Right",
type: "number",
},
]}
headerText="Price Details"
textAlign="Center"
></ColumnDirective>
</ColumnsDirective>
<Inject services={[Page, Toolbar, ColumnChooser,]} />
</TreeGridComponent>
</div>
</div>
);
};
export default App;