Column Groups (Object Model) (Vue)

In addition to the possibility to define grid's columnGroups property using a POJO array, you can use reactive ColumnGroupCollection of ColumnGroup objects for this purpose. In frameworks, you can use corresponding components in framework templates, along with cell templates defining cells and group headers content.

This object model gives you a possibility to change group properties and to restructure the groups tree without recreating the whole tree.

Learn about FlexGrid | FlexGrid API Reference

This example uses Vue.

app.vue
index.html
data.js
Copy to CodeMine
<template> <div class="container-fluid"> <label> Collapse/Expand Animation <input type="checkbox" v-model="animated" /> </label> <label> Use cell templates <input type="checkbox" v-model="useCellTemplates" /> </label> <div v-bind:class="{ animated: animated }"> <wj-flex-grid headersVisibility="Column" showSelectedHeaders="All" :alternatingRowStep="0" :showMarquee="true" :autoGenerateColumns="false" :itemsSource="data"> <wj-flex-grid-column-group binding="name" header="Name" :width="150" /> <wj-flex-grid-column-group binding="currency" header="Curr" :width="80" align="center" /> <wj-flex-grid-column-group ref="allocGr" header="Allocation" align="center" collapseTo="alloc.amount"> <wj-flex-grid-cell-template cellType="ColumnHeader" :autoSizeRows="false" v-if="useCellTemplates" v-slot="cell"> <input type="checkbox" v-model="allocGr.isCollapsed"> {{ cell.col.header }} </wj-flex-grid-cell-template> <wj-flex-grid-column-group binding="alloc.stock" header="Stocks" format="p0" :width="80"> <wj-flex-grid-cell-template cellType="Cell" v-if="useCellTemplates" v-slot="cell"> <span :class="cell.row.grid.getCellData(cell.row.index, cell.col.index, false) > .2 ? 'big-val' : 'small-val'"> {{ cell.row.grid.getCellData(cell.row.index, cell.col.index, true) }} </span> </wj-flex-grid-cell-template> </wj-flex-grid-column-group> <wj-flex-grid-column-group binding="alloc.bond" header="Bonds" format="p0" :width="80"> <wj-flex-grid-cell-template cellType="Cell" v-if="useCellTemplates" v-slot="cell"> <span :class="cell.row.grid.getCellData(cell.row.index, cell.col.index, false) > .2 ? 'big-val' : 'small-val'"> {{ cell.row.grid.getCellData(cell.row.index, cell.col.index, true) }} </span> </wj-flex-grid-cell-template> </wj-flex-grid-column-group> <wj-flex-grid-column-group header="Detail" align="center"> <wj-flex-grid-column-group binding="alloc.cash" header="Cash" format="p0" :width="80"> <wj-flex-grid-cell-template cellType="Cell" v-if="useCellTemplates" v-slot="cell"> <span :class="cell.row.grid.getCellData(cell.row.index, cell.col.index, false) > .2 ? 'big-val' : 'small-val'"> {{ cell.row.grid.getCellData(cell.row.index, cell.col.index, true) }} </span> </wj-flex-grid-cell-template> </wj-flex-grid-column-group> <wj-flex-grid-column-group binding="alloc.other" header="Other" format="p0" :width="80"> <wj-flex-grid-cell-template cellType="Cell" v-if="useCellTemplates" v-slot="cell"> <span :class="cell.row.grid.getCellData(cell.row.index, cell.col.index, false) > .2 ? 'big-val' : 'small-val'"> {{ cell.row.grid.getCellData(cell.row.index, cell.col.index, true) }} </span> </wj-flex-grid-cell-template> </wj-flex-grid-column-group> </wj-flex-grid-column-group> <wj-flex-grid-column-group binding="alloc.amount" header="Amount" format="c0" :width="100" cssClass="main-column" /> </wj-flex-grid-column-group> <wj-flex-grid-column-group header="Perf" align="center"> <wj-flex-grid-column-group header="Short" align="center" collapseTo="perf.ytd" :isCollapsed="true"> <wj-flex-grid-column-group binding="perf.ytd" header="YTD" format="p2" :width="100" cssClass="main-column" /> <wj-flex-grid-column-group binding="perf.m1" header="1 M" format="p2" :width="80" /> </wj-flex-grid-column-group> <wj-flex-grid-column-group header="Long" align="center" collapseTo="perf.m12" :isCollapsed="true"> <wj-flex-grid-column-group binding="perf.m6" header="6 M" format="p2" :width="80" /> <wj-flex-grid-column-group binding="perf.m12" header="12 M" format="p2" :width="100" cssClass="main-column" /> </wj-flex-grid-column-group> </wj-flex-grid-column-group> </wj-flex-grid> </div> </div> </template> <script setup> import "https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/css/flag-icon.css"; import * as DataService from "./data"; import { ref, onMounted } from "vue"; const data = ref(DataService.getData()); const animated = ref(true); const useCellTemplates = ref(true); const allocGr = ref(null); // Ensure allocGr is bound correctly after the component is mounted onMounted(() => { if (allocGr.value && allocGr.value.control) { allocGr.value = allocGr.value.control; } }); </script> <style> label { display: block !important; } .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; } </style>
<template> <div class="container-fluid"> <label> Collapse/Expand Animation <input type="checkbox" v-model="animated" /> </label> <label> Use cell templates <input type="checkbox" v-model="useCellTemplates" /> </label> <div v-bind:class="{ animated: animated }"> <wj-flex-grid headersVisibility="Column" showSelectedHeaders="All" :alternatingRowStep="0" :showMarquee="true" :autoGenerateColumns="false" :itemsSource="data"> <wj-flex-grid-column-group binding="name" header="Name" :width="150" /> <wj-flex-grid-column-group binding="currency" header="Curr" :width="80" align="center" /> <wj-flex-grid-column-group ref="allocGr" header="Allocation" align="center" collapseTo="alloc.amount"> <wj-flex-grid-cell-template cellType="ColumnHeader" :autoSizeRows="false" v-if="useCellTemplates" v-slot="cell"> <input type="checkbox" v-model="allocGr.isCollapsed"> {{ cell.col.header }} </wj-flex-grid-cell-template> <wj-flex-grid-column-group binding="alloc.stock" header="Stocks" format="p0" :width="80"> <wj-flex-grid-cell-template cellType="Cell" v-if="useCellTemplates" v-slot="cell"> <span :class="cell.row.grid.getCellData(cell.row.index, cell.col.index, false) > .2 ? 'big-val' : 'small-val'"> {{ cell.row.grid.getCellData(cell.row.index, cell.col.index, true) }} </span> </wj-flex-grid-cell-template> </wj-flex-grid-column-group> <wj-flex-grid-column-group binding="alloc.bond" header="Bonds" format="p0" :width="80"> <wj-flex-grid-cell-template cellType="Cell" v-if="useCellTemplates" v-slot="cell"> <span :class="cell.row.grid.getCellData(cell.row.index, cell.col.index, false) > .2 ? 'big-val' : 'small-val'"> {{ cell.row.grid.getCellData(cell.row.index, cell.col.index, true) }} </span> </wj-flex-grid-cell-template> </wj-flex-grid-column-group> <wj-flex-grid-column-group header="Detail" align="center"> <wj-flex-grid-column-group binding="alloc.cash" header="Cash" format="p0" :width="80"> <wj-flex-grid-cell-template cellType="Cell" v-if="useCellTemplates" v-slot="cell"> <span :class="cell.row.grid.getCellData(cell.row.index, cell.col.index, false) > .2 ? 'big-val' : 'small-val'"> {{ cell.row.grid.getCellData(cell.row.index, cell.col.index, true) }} </span> </wj-flex-grid-cell-template> </wj-flex-grid-column-group> <wj-flex-grid-column-group binding="alloc.other" header="Other" format="p0" :width="80"> <wj-flex-grid-cell-template cellType="Cell" v-if="useCellTemplates" v-slot="cell"> <span :class="cell.row.grid.getCellData(cell.row.index, cell.col.index, false) > .2 ? 'big-val' : 'small-val'"> {{ cell.row.grid.getCellData(cell.row.index, cell.col.index, true) }} </span> </wj-flex-grid-cell-template> </wj-flex-grid-column-group> </wj-flex-grid-column-group> <wj-flex-grid-column-group binding="alloc.amount" header="Amount" format="c0" :width="100" cssClass="main-column" /> </wj-flex-grid-column-group> <wj-flex-grid-column-group header="Perf" align="center"> <wj-flex-grid-column-group header="Short" align="center" collapseTo="perf.ytd" :isCollapsed="true"> <wj-flex-grid-column-group binding="perf.ytd" header="YTD" format="p2" :width="100" cssClass="main-column" /> <wj-flex-grid-column-group binding="perf.m1" header="1 M" format="p2" :width="80" /> </wj-flex-grid-column-group> <wj-flex-grid-column-group header="Long" align="center" collapseTo="perf.m12" :isCollapsed="true"> <wj-flex-grid-column-group binding="perf.m6" header="6 M" format="p2" :width="80" /> <wj-flex-grid-column-group binding="perf.m12" header="12 M" format="p2" :width="100" cssClass="main-column" /> </wj-flex-grid-column-group> </wj-flex-grid-column-group> </wj-flex-grid> </div> </div> </template> <script setup> import "https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/css/flag-icon.css"; import * as DataService from "./data"; import { ref, onMounted } from "vue"; const data = ref(DataService.getData()); const animated = ref(true); const useCellTemplates = ref(true); const allocGr = ref(null); // Ensure allocGr is bound correctly after the component is mounted onMounted(() => { if (allocGr.value && allocGr.value.control) { allocGr.value = allocGr.value.control; } }); </script> <style> label { display: block !important; } .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; } </style>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>MESCIUS Wijmo FlexGrid Column Groups with Templates</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="compiler.js" type="module"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.21.5/system.src.js" integrity="sha512-skZbMyvYdNoZfLmiGn5ii6KmklM82rYX2uWctBhzaXPxJgiv4XBwJnFGr5k8s+6tE1pcR1nuTKghozJHyzMcoA==" crossorigin="anonymous"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app.js'); </script> </head> <body> <div id="app"> </div> </body> </html>
// get some sample data export 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 } }]; }
(function (global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, meta: { '*.css': { loader: 'css' }, '*.vue': { loader: '../plugin-vue/index.js' } //'*.vue': { loader: 'systemjs-plugin-vue' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { '@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.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.touch': 'npm:@mescius/wijmo.touch/index.js', '@mescius/wijmo.cloud': 'npm:@mescius/wijmo.cloud/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.vue2.chart.analytics": "npm:@mescius/wijmo.vue2.chart.analytics/index.js", "@mescius/wijmo.vue2.chart.animation": "npm:@mescius/wijmo.vue2.chart.animation/index.js", "@mescius/wijmo.vue2.chart.annotation": "npm:@mescius/wijmo.vue2.chart.annotation/index.js", "@mescius/wijmo.vue2.chart.finance.analytics": "npm:@mescius/wijmo.vue2.chart.finance.analytics/index.js", "@mescius/wijmo.vue2.chart.finance": "npm:@mescius/wijmo.vue2.chart.finance/index.js", "@mescius/wijmo.vue2.chart.hierarchical": "npm:@mescius/wijmo.vue2.chart.hierarchical/index.js", "@mescius/wijmo.vue2.chart.interaction": "npm:@mescius/wijmo.vue2.chart.interaction/index.js", "@mescius/wijmo.vue2.chart.radar": "npm:@mescius/wijmo.vue2.chart.radar/index.js", '@mescius/wijmo.vue2.chart.map': 'npm:@mescius/wijmo.vue2.chart.map/index.js', "@mescius/wijmo.vue2.chart": "npm:@mescius/wijmo.vue2.chart/index.js", "@mescius/wijmo.vue2.core": "npm:@mescius/wijmo.vue2.core/index.js", "@mescius/wijmo.vue2.gauge": "npm:@mescius/wijmo.vue2.gauge/index.js", "@mescius/wijmo.vue2.grid.detail": "npm:@mescius/wijmo.vue2.grid.detail/index.js", "@mescius/wijmo.vue2.grid.filter": "npm:@mescius/wijmo.vue2.grid.filter/index.js", "@mescius/wijmo.vue2.grid.grouppanel": "npm:@mescius/wijmo.vue2.grid.grouppanel/index.js", '@mescius/wijmo.vue2.grid.search': 'npm:@mescius/wijmo.vue2.grid.search/index.js', "@mescius/wijmo.vue2.grid.multirow": "npm:@mescius/wijmo.vue2.grid.multirow/index.js", "@mescius/wijmo.vue2.grid.sheet": "npm:@mescius/wijmo.vue2.grid.sheet/index.js", '@mescius/wijmo.vue2.grid.transposed': 'npm:@mescius/wijmo.vue2.grid.transposed/index.js', '@mescius/wijmo.vue2.grid.transposedmultirow': 'npm:@mescius/wijmo.vue2.grid.transposedmultirow/index.js', "@mescius/wijmo.vue2.grid": "npm:@mescius/wijmo.vue2.grid/index.js", "@mescius/wijmo.vue2.input": "npm:@mescius/wijmo.vue2.input/index.js", "@mescius/wijmo.vue2.olap": "npm:@mescius/wijmo.vue2.olap/index.js", "@mescius/wijmo.vue2.viewer": "npm:@mescius/wijmo.vue2.viewer/index.js", "@mescius/wijmo.vue2.nav": "npm:@mescius/wijmo.vue2.nav/index.js", "@mescius/wijmo.vue2.base": "npm:@mescius/wijmo.vue2.base/index.js", '@mescius/wijmo.vue2.barcode.common': 'npm:@mescius/wijmo.vue2.barcode.common/index.js', '@mescius/wijmo.vue2.barcode.composite': 'npm:@mescius/wijmo.vue2.barcode.composite/index.js', '@mescius/wijmo.vue2.barcode.specialized': 'npm:@mescius/wijmo.vue2.barcode.specialized/index.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', 'jszip': 'npm:jszip/dist/jszip.js', 'css': 'npm:systemjs-plugin-css/css.js', 'vue': 'npm:vue/dist/vue.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', 'vue-loader': 'npm:systemjs-vue-browser/index.js', //'systemjs-plugin-vue': 'npm:systemjs-plugin-vue/index.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel/systemjs-babel-browser.js' }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'js' }, rxjs: { defaultExtension: 'js' }, "node_modules": { defaultExtension: 'js' }, wijmo: { defaultExtension: 'js', } } }); })(this);