Master / detail
detailRenderer opens a panel under a row with anything in it, such as another grid; isRowMaster limits which rows can open one.
Live demoMaster / detail
A panel under a row with anything in it, here another grid.
Code for this demo
import { createGrid } from '@freegridjs/core';
import { makeRows } from '../data';
import { button, separator, text, tr, type DemoContext } from '../ui';
export default function mount(ctx: DemoContext) {
const { lang } = ctx;
const h = (en: string, ko: string) => tr(lang, { en, ko });
const data = makeRows(200);
const first = data.find(r => r.active)!;
const grid = createGrid(ctx.host, {
columns: [
{ field: 'name', header: h('Name', '이름'), width: 190 },
{ field: 'company', header: h('Company', '회사'), width: 140 },
{ field: 'country', header: h('Country', '국가'), width: 140 },
{ field: 'total', header: h('Total', '합계'), type: 'number', format: '#,##0', width: 130 },
{ field: 'active', header: h('Active', '활성'), type: 'boolean', width: 90 },
],
data,
locale: lang,
detailHeight: 180,
// only active customers have a detail panel
isRowMaster: row => row.active,
detailRenderer: ({ row }) => {
// a small grid inside the panel: the person's quarters
const el = document.createElement('div');
el.style.height = '158px';
createGrid(el, {
columns: [
{ field: 'quarter', header: h('Quarter', '분기'), width: 120 },
{ field: 'revenue', header: h('Revenue', '매출'), type: 'number', format: '#,##0', width: 160 },
],
data: ['q1', 'q2', 'q3', 'q4'].map((q, i) => ({ quarter: `${i + 1}Q`, revenue: row[q] })),
locale: lang,
rowHeight: 26,
});
return el;
},
});
grid.on('detailToggle', e => ctx.log(`detailToggle → ${e.row.name}: ${e.expanded}`));
text(ctx, h('Press the arrow in front of a name: a panel with another grid opens under the row. Inactive people have no panel.',
'이름 앞 화살표를 누르면 행 아래에 다른 그리드가 든 패널이 열립니다. 비활성 사용자는 패널이 없습니다.'));
separator(ctx);
button(ctx, h('Open the first panel', '첫 패널 열기'), () => grid.setDetailExpanded(first, true));
button(ctx, h('Close it', '첫 패널 닫기'), () => grid.setDetailExpanded(first, false));
button(ctx, h('Open all', '모두 펼치기'), () => grid.setAllDetailsExpanded(true));
button(ctx, h('Close all', '모두 접기'), () => grid.setAllDetailsExpanded(false));
return grid;
}Master / detail puts an expandable panel under a row. An arrow appears in the first column; pressing it opens a full-width panel with whatever detailRenderer returns: the lines of an order in another grid, a form, a chart or plain HTML. Panels scroll with their row and keep their height (detailHeight, 240 px by default).
isRowMaster limits which rows can open a panel, for example only orders that have lines. Open and close panels from code with setDetailExpanded, and listen for detailToggle to load data when a panel opens. A grid inside a panel is an ordinary grid with its own options and events.
createGrid(el, {
columns,
data: orders,
detailHeight: 200, // px, default 240
isRowMaster: row => row.items?.length > 0, // only these rows get the toggle
detailRenderer: ({ row }) => {
// anything: HTML text, an element, or another grid
const box = document.createElement('div');
box.style.height = '180px';
createGrid(box, { columns: itemColumns, data: row.items });
return box;
},
});
grid.setDetailExpanded(orders[0], true);
grid.isDetailExpanded(orders[0]); // true
grid.on('detailToggle', e => console.log(e.row.id, e.expanded));A string from detailRenderer is inserted as HTML. Escape data that comes from users, or return an element.
Open at the start, open or close all
detailExpanded opens details at the start, and setAllDetailsExpanded() opens or closes them all. See:
Options, methods and events
| Name | Type | Description |
|---|---|---|
detailRenderer({ row, rowIndex }) | HTMLElement | string | Content of the panel under a row: an element (another grid, a form, a chart) or HTML text. Escape data you put in HTML text. |
detailExpanded / setAllDetailsExpanded(open) | boolean | (row) => boolean / void | Rows that start opened; open or close every detail row (detailToggleAll event). |
detailHeight | number | Height of the panel in px (default 240). |
isRowMaster(row) | boolean | Which rows can open a panel (default: all rows). |
setDetailExpanded(row, open) / isDetailExpanded(row) | void / boolean | Open, close or check a panel from code. |
detailToggle | { row, expanded } (event) | A panel opened or closed. |
Questions about this page
Can a row expand to show another grid?
Yes. detailRenderer returns an element for the panel under the row, which can hold another grid; isRowMaster decides which rows can expand.