Column Groups (React)

This sample shows how you can create column groups by initializing the grid's columnGroups collection with an array of hierarchical elements where columns may have a columns property containing child columns.

The column groups may be collapsible and configured to show any of the child columns when the group is collapsed.

You can use CSS to animate the column groups as they expand or collapse.

Learn about FlexGrid | FlexGrid API Reference

This example uses React.

import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import ReactDOM from 'react-dom/client'; import React, { useState, useRef } from 'react'; import { FlexGrid } from '@mescius/wijmo.react.grid'; import './app.css'; import { colGroups1, colGroups2, data } from './data'; function App() { const [animated, setAnimated] = useState(true); const gridRef = useRef(null); return (<main className="container-fluid"> <label> Collapse/Expand Animation{' '} <input type="checkbox" checked={animated} onChange={() => setAnimated(!animated)}/> </label> <button id="toggle" className="btn btn-primary" onClick={() => { const cols = gridRef.current.control.columnGroups; gridRef.current.control.columnGroups = cols == colGroups1 ? colGroups2 : colGroups1; }}> Toggle Column Groups </button> <div className={animated ? 'animated' : ''}> <FlexGrid ref={gridRef} initialized={(grid) => grid.columnGroups = colGroups1} headersVisibility="Column" alternatingRowStep={0} showMarquee={true} showSelectedHeaders="All" autoGenerateColumns={false} itemsSource={data}/> </div> </main>); } const container = document.getElementById('app'); if (container) { const root = ReactDOM.createRoot(container); root.render(<App />); }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>MESCIUS Wijmo Wijmo FlexGrid Column Groups</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.40/system.src.js" integrity="sha512-G6mEj6h18+m3MvzdviSDfPle/TfH0//cXcB33AKlNR/Rha0yQsKefDZKRTkIZos97HEGq2JMV1RT5ybMoQ3WsQ==" crossorigin="anonymous"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div id="app"></div> </body> </html>
label { display: block; } .wj-flexgrid { margin: 10px 0; } /* highlight the main column in the group */ .wj-flexgrid .wj-cells .wj-cell.main-column { background: #e3f4ff; } /* some conditional formatting */ .big-val { font-weight: bold; color: darkgreen; } .small-val { font-style: italic; color: rgb(202, 0, 0); } /* some animation when collapsing/expanding the groups */ .animated .wj-flexgrid .wj-colheaders .wj-header.wj-cell.wj-colgroup { transition: all .2s; }
import * as wijmo from "@mescius/wijmo"; // get an array with hierarchical column definitions the 'columns' property of the objects contain child columns the 'collapseTo' property specifies the binding of thei child column that should remain visible when the group is collapsed. function getColumnGroups() { const allocTemplate = (ctx) => (`<span class=${ctx.value > .2 ? "big-val" : "small-val"}> ${wijmo.Globalize.format(ctx.value, ctx.col.format)} </span>`); const amountTemplate = (ctx) => (`<span class=${ctx.value > 50000 ? "big-val" : "small-val"}> ${wijmo.Globalize.format(ctx.value, ctx.col.format)}</span>`); return [ { binding: 'name', header: 'Name', width: 150 }, { binding: 'currency', header: 'Curr', width: 80, align: 'center' }, { header: 'Perf', align: 'center', collapseTo: 'perf.ytd', columns: [ { binding: 'perf.ytd', header: 'YTD', format: 'p2', width: 100, cssClass: 'main-column' }, { binding: 'perf.m1', header: '1 M', format: 'p2', width: 80 }, { binding: 'perf.m6', header: '6 M', format: 'p2', width: 80 }, { binding: 'perf.m12', header: '12 M', format: 'p2', width: 80 }, ] }, { header: 'Allocation', align: 'center', collapseTo: 'alloc.amount', columns: [ { binding: 'alloc.stock', header: 'Stocks', format: 'p0', width: 80, cellTemplate: allocTemplate }, { binding: 'alloc.bond', header: 'Bonds', format: 'p0', width: 80, cellTemplate: allocTemplate }, { binding: 'alloc.cash', header: 'Cash', format: 'p0', width: 80, cellTemplate: allocTemplate }, { binding: 'alloc.other', header: 'Other', format: 'p0', width: 80, cellTemplate: allocTemplate }, { binding: 'alloc.amount', header: 'Amount', format: 'c0', width: 100, cssClass: 'main-column', cellTemplate: amountTemplate } ] } ]; } // slightly different column groups function getDeeperColumnGroups() { return [ { binding: 'name', header: 'Name', width: 150 }, { binding: 'currency', header: 'Curr', width: 80, align: 'center' }, { header: 'Allocation', align: 'center', collapseTo: 'alloc.amount', columns: [ { binding: 'alloc.stock', header: 'Stocks', format: 'p0', width: 80 }, { binding: 'alloc.bond', header: 'Bonds', format: 'p0', width: 80 }, { header: 'Detail', align: 'center', columns: [ { binding: 'alloc.cash', header: 'Cash', format: 'p0', width: 80 }, { binding: 'alloc.other', header: 'Other', format: 'p0', width: 80 }, ] }, { binding: 'alloc.amount', header: 'Amount', format: 'c0', width: 100, cssClassAll: 'main-column' }, ] }, { header: 'Perf', align: 'center', columns: [ { header: 'Short', align: 'center', collapseTo: 'perf.ytd', isCollapsed: true, columns: [ { binding: 'perf.ytd', header: 'YTD', format: 'p2', width: 100, cssClassAll: 'main-column' }, { binding: 'perf.m1', header: '1 M', format: 'p2', width: 80 }, ] }, { header: 'Long', align: 'center', collapseTo: 'perf.m12', isCollapsed: true, columns: [ { binding: 'perf.m6', header: '6 M', format: 'p2', width: 80 }, { binding: 'perf.m12', header: '12 M', format: 'p2', width: 100, cssClassAll: 'main-column' } ] }, ] }, ]; } // get some sample data function getData() { return [{ name: 'Constant Growth', currency: 'USD', perf: { ytd: .0523, m1: 0.0142, m6: 0.0443, m12: 0.0743 }, alloc: { stock: 0.17, bond: 0.32, cash: 0.36, other: 0.15, amount: 23432 } }, { name: 'Optimus Prime', currency: 'EUR', perf: { ytd: .0343, m1: 0.043, m6: 0.0244, m12: 0.0543 }, alloc: { stock: 0.61, bond: 0.8, cash: 0.9, other: 0.22, amount: 43223 } }, { name: 'Crypto Planet', currency: 'BTC', perf: { ytd: .0343, m1: 0.014, m6: 0.034, m12: 0.01243 }, alloc: { stock: 0.1, bond: 0, cash: 0, other: 0.9, amount: 2234 } }, { name: 'MegaZone', currency: 'EUR', perf: { ytd: .0443, m1: 0.034, m6: 0.0424, m12: 0.0343 }, alloc: { stock: 0.51, bond: 0.9, cash: 0.8, other: 0.12, amount: 32234 } }, { name: 'Serenity', currency: 'YEN', perf: { ytd: .0522, m1: 0.0143, m6: 0.0458, m12: 0.0732 }, alloc: { stock: 0.66, bond: 0.09, cash: 0.19, other: 0.06, amount: 65624 } }]; } export const colGroups1 = getColumnGroups(); export const colGroups2 = getDeeperColumnGroups(); export const data = getData();
(function (global) { window.process = { env: { NODE_ENV: "production" } } System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true, react: true }, meta: { '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { 'jszip': 'npm:jszip/dist/jszip.js', '@mescius/wijmo': 'npm:@mescius/wijmo/index.js', '@mescius/wijmo.input': 'npm:@mescius/wijmo.input/index.js', '@mescius/wijmo.styles': 'npm:@mescius/wijmo.styles', '@mescius/wijmo.cultures': 'npm:@mescius/wijmo.cultures', '@mescius/wijmo.chart': 'npm:@mescius/wijmo.chart/index.js', '@mescius/wijmo.chart.analytics': 'npm:@mescius/wijmo.chart.analytics/index.js', '@mescius/wijmo.chart.animation': 'npm:@mescius/wijmo.chart.animation/index.js', '@mescius/wijmo.chart.annotation': 'npm:@mescius/wijmo.chart.annotation/index.js', '@mescius/wijmo.chart.finance': 'npm:@mescius/wijmo.chart.finance/index.js', '@mescius/wijmo.chart.finance.analytics': 'npm:@mescius/wijmo.chart.finance.analytics/index.js', '@mescius/wijmo.chart.hierarchical': 'npm:@mescius/wijmo.chart.hierarchical/index.js', '@mescius/wijmo.chart.interaction': 'npm:@mescius/wijmo.chart.interaction/index.js', '@mescius/wijmo.chart.radar': 'npm:@mescius/wijmo.chart.radar/index.js', '@mescius/wijmo.chart.render': 'npm:@mescius/wijmo.chart.render/index.js', '@mescius/wijmo.chart.webgl': 'npm:@mescius/wijmo.chart.webgl/index.js', '@mescius/wijmo.chart.map': 'npm:@mescius/wijmo.chart.map/index.js', '@mescius/wijmo.gauge': 'npm:@mescius/wijmo.gauge/index.js', '@mescius/wijmo.grid': 'npm:@mescius/wijmo.grid/index.js', '@mescius/wijmo.grid.detail': 'npm:@mescius/wijmo.grid.detail/index.js', '@mescius/wijmo.grid.filter': 'npm:@mescius/wijmo.grid.filter/index.js', '@mescius/wijmo.grid.search': 'npm:@mescius/wijmo.grid.search/index.js', '@mescius/wijmo.grid.style': 'npm:@mescius/wijmo.grid.style/index.js', '@mescius/wijmo.grid.grouppanel': 'npm:@mescius/wijmo.grid.grouppanel/index.js', '@mescius/wijmo.grid.multirow': 'npm:@mescius/wijmo.grid.multirow/index.js', '@mescius/wijmo.grid.transposed': 'npm:@mescius/wijmo.grid.transposed/index.js', '@mescius/wijmo.grid.transposedmultirow': 'npm:@mescius/wijmo.grid.transposedmultirow/index.js', '@mescius/wijmo.grid.pdf': 'npm:@mescius/wijmo.grid.pdf/index.js', '@mescius/wijmo.grid.sheet': 'npm:@mescius/wijmo.grid.sheet/index.js', '@mescius/wijmo.grid.xlsx': 'npm:@mescius/wijmo.grid.xlsx/index.js', '@mescius/wijmo.grid.selector': 'npm:@mescius/wijmo.grid.selector/index.js', '@mescius/wijmo.grid.cellmaker': 'npm:@mescius/wijmo.grid.cellmaker/index.js', '@mescius/wijmo.grid.immutable': 'npm:@mescius/wijmo.grid.immutable/index.js', '@mescius/wijmo.touch': 'npm:@mescius/wijmo.touch/index.js', '@mescius/wijmo.cloud': 'npm:@mescius/wijmo.cloud/index.js', '@mescius/wijmo.nav': 'npm:@mescius/wijmo.nav/index.js', '@mescius/wijmo.odata': 'npm:@mescius/wijmo.odata/index.js', '@mescius/wijmo.olap': 'npm:@mescius/wijmo.olap/index.js', '@mescius/wijmo.rest': 'npm:@mescius/wijmo.rest/index.js', '@mescius/wijmo.pdf': 'npm:@mescius/wijmo.pdf/index.js', '@mescius/wijmo.pdf.security': 'npm:@mescius/wijmo.pdf.security/index.js', '@mescius/wijmo.viewer': 'npm:@mescius/wijmo.viewer/index.js', '@mescius/wijmo.xlsx': 'npm:@mescius/wijmo.xlsx/index.js', '@mescius/wijmo.undo': 'npm:@mescius/wijmo.undo/index.js', '@mescius/wijmo.interop.grid': 'npm:@mescius/wijmo.interop.grid/index.js', '@mescius/wijmo.barcode': 'npm:@mescius/wijmo.barcode/index.js', '@mescius/wijmo.barcode.common': 'npm:@mescius/wijmo.barcode.common/index.js', '@mescius/wijmo.barcode.composite': 'npm:@mescius/wijmo.barcode.composite/index.js', '@mescius/wijmo.barcode.specialized': 'npm:@mescius/wijmo.barcode.specialized/index.js', "@mescius/wijmo.react.chart.analytics": "npm:@mescius/wijmo.react.chart.analytics/index.js", "@mescius/wijmo.react.chart.animation": "npm:@mescius/wijmo.react.chart.animation/index.js", "@mescius/wijmo.react.chart.annotation": "npm:@mescius/wijmo.react.chart.annotation/index.js", "@mescius/wijmo.react.chart.finance.analytics": "npm:@mescius/wijmo.react.chart.finance.analytics/index.js", "@mescius/wijmo.react.chart.finance": "npm:@mescius/wijmo.react.chart.finance/index.js", "@mescius/wijmo.react.chart.hierarchical": "npm:@mescius/wijmo.react.chart.hierarchical/index.js", "@mescius/wijmo.react.chart.interaction": "npm:@mescius/wijmo.react.chart.interaction/index.js", "@mescius/wijmo.react.chart.radar": "npm:@mescius/wijmo.react.chart.radar/index.js", "@mescius/wijmo.react.chart": "npm:@mescius/wijmo.react.chart/index.js", "@mescius/wijmo.react.core": "npm:@mescius/wijmo.react.core/index.js", '@mescius/wijmo.react.chart.map': 'npm:@mescius/wijmo.react.chart.map/index.js', "@mescius/wijmo.react.gauge": "npm:@mescius/wijmo.react.gauge/index.js", "@mescius/wijmo.react.grid.detail": "npm:@mescius/wijmo.react.grid.detail/index.js", "@mescius/wijmo.react.grid.filter": "npm:@mescius/wijmo.react.grid.filter/index.js", "@mescius/wijmo.react.grid.grouppanel": "npm:@mescius/wijmo.react.grid.grouppanel/index.js", '@mescius/wijmo.react.grid.search': 'npm:@mescius/wijmo.react.grid.search/index.js', "@mescius/wijmo.react.grid.multirow": "npm:@mescius/wijmo.react.grid.multirow/index.js", "@mescius/wijmo.react.grid.sheet": "npm:@mescius/wijmo.react.grid.sheet/index.js", '@mescius/wijmo.react.grid.transposed': 'npm:@mescius/wijmo.react.grid.transposed/index.js', '@mescius/wijmo.react.grid.transposedmultirow': 'npm:@mescius/wijmo.react.grid.transposedmultirow/index.js', '@mescius/wijmo.react.grid.immutable': 'npm:@mescius/wijmo.react.grid.immutable/index.js', "@mescius/wijmo.react.grid": "npm:@mescius/wijmo.react.grid/index.js", "@mescius/wijmo.react.input": "npm:@mescius/wijmo.react.input/index.js", "@mescius/wijmo.react.olap": "npm:@mescius/wijmo.react.olap/index.js", "@mescius/wijmo.react.viewer": "npm:@mescius/wijmo.react.viewer/index.js", "@mescius/wijmo.react.nav": "npm:@mescius/wijmo.react.nav/index.js", "@mescius/wijmo.react.base": "npm:@mescius/wijmo.react.base/index.js", '@mescius/wijmo.react.barcode.common': 'npm:@mescius/wijmo.react.barcode.common/index.js', '@mescius/wijmo.react.barcode.composite': 'npm:@mescius/wijmo.react.barcode.composite/index.js', '@mescius/wijmo.react.barcode.specialized': 'npm:@mescius/wijmo.react.barcode.specialized/index.js', 'jszip': 'npm:jszip/dist/jszip.js', 'react': 'npm:react/index.js', 'react-dom': 'npm:react-dom/index.js', 'react-dom/client': 'npm:react-dom/client.js', "scheduler": "npm:scheduler/index.js", 'redux': 'npm:redux/dist/redux.min.js', 'react-redux': 'npm:react-redux/dist/react-redux.min.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', 'css': 'npm:systemjs-plugin-css/css.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js', "react-use-event-hook": "npm:react-use-event-hook/dist/esm/useEvent.js", }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'jsx' }, "node_modules": { defaultExtension: 'js' }, } }); })(this);