Expanding FlexGrid Rows to Show Full Text in Vue
Background:
When using Wijmo FlexGrid, some cells may contain long text values that are truncated because rows use a fixed height. In this scenario, users may need a way to expand only the row they are viewing, show the full wrapped text, and then collapse the row again.
FlexGrid does not require the Row Detail plugin for this specific use case. Row Detail is better when you need to show an additional detail panel below a row. For simply showing more text inside the existing cells, a lighter approach is to toggle the row’s wordWrap property and call autoSizeRow for the selected row.
The process involves adding a custom expand/collapse icon to the row header, checking whether the target cell content is overflowing, and resizing the row when the icon is clicked.
Steps to Complete:
- Install Wijmo packages.
- Import Wijmo styles.
- Create a FlexGrid with long text content.
- Add a row header template with expand/collapse icons.
- Handle icon clicks and toggle row word wrapping.
- Auto-size the selected row.
Getting Started:
Install Wijmo packages
Ensure the required Wijmo Vue packages are available in your project.
npm i @mescius/wijmo @mescius/wijmo.vue2.grid @mescius/wijmo.styles
@mescius/wijmo.vue2.gridincludes the Vue wrapper forFlexGrid.@mescius/wijmoincludes the core Wijmo utilities.@mescius/wijmo.stylesincludes the default Wijmo CSS.
Import Wijmo styles
Import the Wijmo CSS file in your main entry file.
import { createApp } from 'vue';
import App from './App.vue';
import '@mescius/wijmo.styles/wijmo.css';
import './style.css';
createApp(App).mount('#app');
- If this step is missed, the grid and built-in Wijmo glyph icons will not display correctly.
Create a FlexGrid with long text content
This creates the grid and binds it to data that includes a long text field. In this example, the description column contains text that may be too long to fit inside the default row height.
<template>
<div class="app">
<wj-flex-grid :items-source="data">
</wj-flex-grid>
</div>
</template>
<script>
import { WjFlexGrid } from '@mescius/wijmo.vue2.grid';
export default {
name: 'App',
components: {
WjFlexGrid
},
data() {
return {
data: this.getData(1000)
};
},
methods: {
getData(count) {
const countries = 'US,Germany,UK,Japan,Italy,Greece'.split(',');
const data = [];
for (let i = 0; i < count; i++) {
data.push({
id: i,
country: countries[i % countries.length],
description:
i % 2 === 0
? 'This is a long description designed to overflow the cell text. This is a long description designed to overflow the cell text.'
: 'Description',
active: i % 4 === 0
});
}
return data;
}
}
};
</script>
Add a row header template with expand/collapse icons
This adds a custom template to the row header. The template checks whether the target cell content is overflowing. If the row is collapsed and the text overflows, it shows a plus icon. If the row is expanded, it shows a minus icon.
<template>
<div class="app">
<wj-flex-grid
:items-source="data"
:virtualization-threshold="[0, 50]"
:initialized="initGrid"
>
<wj-flex-grid-cell-template
cellType="RowHeader"
v-slot="cell"
>
<span
v-if="shouldShowExpandIcon(cell.row)"
class="row-btn wj-glyph-plus"
title="Expand row"
></span>
<span
v-if="shouldShowCollapseIcon(cell.row)"
class="row-btn wj-glyph-minus"
title="Collapse row"
></span>
</wj-flex-grid-cell-template>
</wj-flex-grid>
</div>
</template>
<script>
import { WjFlexGrid, WjFlexGridCellTemplate } from '@mescius/wijmo.vue2.grid';
export default {
name: 'App',
components: {
WjFlexGrid,
WjFlexGridCellTemplate
},
data() {
return {
data: this.getData(1000),
grid: null
};
},
methods: {
shouldShowExpandIcon(row) {
if (!this.grid || !row) {
return false;
}
return this.isOverflow(row) && row.renderHeight <= this.grid.rows.defaultSize;
},
shouldShowCollapseIcon(row) {
if (!this.grid || !row) {
return false;
}
return row.renderHeight > this.grid.rows.defaultSize;
},
isOverflow(row) {
const targetCols = ['description'];
for (let i = 0; i < targetCols.length; i++) {
const col = this.grid.getColumn(targetCols[i]);
if (col) {
const cell = this.grid.cells.getCellElement(row.index, col.index);
if (cell && cell.scrollWidth > cell.clientWidth) {
return true;
}
}
}
return false;
},
getData(count) {
const countries = 'US,Germany,UK,Japan,Italy,Greece'.split(',');
const data = [];
for (let i = 0; i < count; i++) {
data.push({
id: i,
country: countries[i % countries.length],
description:
i % 2 === 0
? 'This is a long description designed to overflow the cell text. This is a long description designed to overflow the cell text.'
: 'Description',
active: i % 4 === 0
});
}
return data;
}
}
};
</script>
Handle icon clicks and toggle row word wrapping
This listens for clicks inside the grid. When the user clicks the plus or minus icon in the row header, the code finds the clicked row and toggles its wordWrap property.
<script>
import * as wjCore from '@mescius/wijmo';
import * as wjGrid from '@mescius/wijmo.grid';
export default {
name: 'App',
data() {
return {
data: this.getData(1000),
grid: null
};
},
methods: {
initGrid(grid) {
this.grid = grid;
grid.rows.defaultSize = 26;
grid.addEventListener(grid.hostElement, 'click', (e) => {
const ht = grid.hitTest(e);
const target = e.target;
if (wjCore.hasClass(target, 'row-btn') && ht.panel === grid.rowHeaders) {
const row = grid.rows[ht.row];
row.wordWrap = row.renderHeight <= grid.rows.defaultSize;
}
});
},
getData(count) {
const countries = 'US,Germany,UK,Japan,Italy,Greece'.split(',');
const data = [];
for (let i = 0; i < count; i++) {
data.push({
id: i,
country: countries[i % countries.length],
description:
i % 2 === 0
? 'This is a long description designed to overflow the cell text. This is a long description designed to overflow the cell text.'
: 'Description',
active: i % 4 === 0
});
}
return data;
}
}
};
</script>
- If the row is currently collapsed,
wordWrapbecomestrue. If the row is already expanded,wordWrapbecomesfalse.
Auto-size the selected row.
Toggling wordWrap alone is not enough. The row also needs to be resized so the wrapped text can actually appear. This is where autoSizeRow comes in.
initGrid(grid) {
this.grid = grid;
grid.rows.defaultSize = 26;
grid.addEventListener(grid.hostElement, 'click', (e) => {
const ht = grid.hitTest(e);
const target = e.target;
if (wjCore.hasClass(target, 'row-btn') && ht.panel === grid.rowHeaders) {
const row = grid.rows[ht.row];
row.wordWrap = row.renderHeight <= grid.rows.defaultSize;
// Resize only the clicked row.
grid.autoSizeRow(row.index);
}
});
}
- Use
grid.autoSizeRow(row.index);immediately after changingrow.wordWrap
With this Vue setup:
- Long text rows show an expand icon in the row header.
- Clicking the icon enables wrapping and auto-sizes that specific row.
- Clicking again disables wrapping and collapses the row.
- Rows without overflowing text do not show an icon.
- The implementation avoids unnecessary row detail panels.
Happy coding!
