FreeGridv1.6.0한국어

Events

Live demoEvents

Every event the grid sends, logged as you click, edit, sort and filter.

Code for this demo
import { createGrid, type GridEvents } from '@freegridjs/core';
import { HEADERS, makeRows } from '../data';
import { button, separator, text, toggle, 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 t = HEADERS[lang];
  const grid = createGrid(ctx.host, {
    columns: [
      { field: 'name', header: t.name, width: 150, editable: true },
      { field: 'country', header: t.country, width: 130, filter: 'set' },
      { field: 'q1', header: t.q1, type: 'number', format: '#,##0', width: 110, editable: true },
      { field: 'growth', header: t.growth, type: 'number', format: '0.0%', width: 100 },
      { field: 'status', header: t.status, width: 100, editable: true, editor: { type: 'select', options: ['Active', 'Pending', 'Closed'] } },
    ],
    data: makeRows(80), locale: lang, getRowId: r => String(r.id), rowSelection: 'multiple', pagination: { pageSize: 20 },
  });

  // each event and a short line for the log; on() returns a function that stops listening
  const show: { [K in keyof GridEvents]?: (e: GridEvents[K]) => string } = {
    cellClick: e => `row ${e.rowIndex}, ${e.colId} = ${String(e.value)}`,
    cellDoubleClick: e => `row ${e.rowIndex}, ${e.colId}`,
    editStart: e => `row ${e.rowIndex}, ${e.colId}`,
    cellValueChanged: e => `${e.colId}: ${String(e.oldValue)} → ${String(e.newValue)}`,
    editStop: e => `committed: ${e.committed}`,
    selectionChange: e => `${e.selected.length} ${h('selected', '개 선택')}`,
    sortChange: e => JSON.stringify(e.sort),
    filterChange: e => Object.keys(e.filters).join(', ') || h('(none)', '(없음)'),
    columnResize: e => `${e.colId} → ${e.width}px`,
    columnMove: e => `${e.colId} → ${e.toIndex}`,
    pageChange: e => `${e.page + 1} / ${e.pageCount}`,
    rangeChange: e => (e.range ? `${e.range.start.colId}${e.range.start.rowIndex}:${e.range.end.colId}${e.range.end.rowIndex}` : '-'),
  };
  const offs = new Map<string, () => void>();
  const listen = (name: keyof GridEvents) => {
    const fmt = show[name] as (e: unknown) => string;
    offs.set(name, grid.on(name, ((e: unknown) => {
      try {
        ctx.log(`${name} → ${fmt(e)}`);
      } catch {
        ctx.log(name);
      }
    }) as never));
  };
  for (const name of Object.keys(show) as (keyof GridEvents)[]) listen(name);

  text(ctx, h('Click, double-click to edit, sort, filter, resize, drag a column, select rows and change pages: every event appears in the log below.',
    '클릭, 더블클릭 편집, 정렬, 필터, 너비 조절, 컬럼 끌기, 행 선택, 페이지 이동을 해 보세요. 모든 이벤트가 아래 기록에 나타납니다.'));
  separator(ctx);
  toggle(ctx, h('Log clicks', '클릭 기록'), true, on => {
    if (on) listen('cellClick');
    else offs.get('cellClick')?.();
  });
  button(ctx, h('Sort from code', '코드로 정렬'), () => grid.setSort([{ colId: 'q1', dir: 'desc' }]));
  return grid;
}

grid.on(name, fn) listens and returns a function that stops listening. The React, Vue, Svelte and Angular wrappers use the same events as onCellClick, @cell-click and (cellClick). Click, edit, sort and filter in the demo above to see which events arrive and in what order.

Common events

// row click → details
grid.on('cellClick', ({ row, colId, value }) => openDetail(row.id));
grid.on('cellDoubleClick', ({ row }) => openEditor(row));

// enable a button while rows are selected
grid.on('selectionChange', ({ selected }) => (deleteBtn.disabled = selected.length === 0));

// save the view when sorting, filters or columns change
const save = () => localStorage.setItem('orders-view', JSON.stringify(grid.getState()));
grid.on('sortChange', save);
grid.on('filterChange', save);
grid.on('columnResize', save);
grid.on('columnMove', save);

// every value change (edit, paste, fill, undo)
grid.on('cellValueChanged', ({ row, colId, oldValue, newValue }) => console.log(row.id, colId, oldValue, '→', newValue));

// stop listening
const off = grid.on('rangeChange', ({ range }) => updateStatus(range));
off();

Events you can cancel (before…)

beforeSort, beforeFilter, beforePageChange, beforeEdit and beforeCellChange come before the change; calling cancel() stops it. Use them for permission checks or to sort on the server instead.

// approved orders cannot be edited
grid.on('beforeEdit', e => { if (e.row.status === 'Approved') e.cancel(); });

// no negative quantities
grid.on('beforeCellChange', e => { if (e.colId === 'qty' && Number(e.newValue) < 0) e.cancel(); });

// sort on the server: stop the grid's sort and reload
grid.on('beforeSort', e => { e.cancel(); reload({ sort: e.sort }); });

Saving edits to the server

// save each edited cell
grid.on('cellValueChanged', async ({ row, colId, newValue }) => {
  await fetch(`/api/orders/${row.id}`, { method: 'PATCH', body: JSON.stringify({ [colId]: newValue }) });
});

// row editing (editType: 'row'): save once per row
grid.on('rowEditStop', ({ row, committed, changes }) => { if (committed && changes.length) saveRow(row); });

// tell people why a value was refused
grid.on('validationFailed', ({ message }) => toast(message));

In frameworks

// React
<FreeGrid columns={columns} data={rows} onCellClick={e => open(e.row)} onSelectionChange={e => setSelected(e.selected)} />

// Vue
<FreeGrid :columns="columns" :data="rows" @cell-click="e => open(e.row)" @selection-change="e => selected = e.selected" />

All events

EventPayloadWhen
cellClick / cellDoubleClick{ row, rowIndex, colId, value, event }A data cell was clicked.
selectionChange{ selected: Row[] }Selected rows changed.
sortChange{ sort }Sort changed.
filterChange{ filters }A column filter changed.
columnResize{ colId, width }Resize or autosize finished.
columnMove{ colId, toIndex }A column was dragged to a new position.
columnVisible{ colId, visible }A column was shown or hidden.
rangeChange{ range }The cell range changed.
cellValueChanged{ row, rowIndex, colId, oldValue, newValue }A paste changed a cell.
paste{ changed, skipped }A paste finished.
editStart / editStop{ rowIndex, colId, committed? }An editor opened or closed.
validationFailed{ rowIndex, colId, value, message }An edited value was rejected.
rowsAdded / rowsRemoved{ rows }Rows were inserted or removed.
groupChange / groupToggle{ groupBy } / { key, expanded }Grouping changed; a group or tree row opened or closed.
detailToggle{ row, expanded }A detail panel opened or closed.
rowDragEnd{ row, fromIndex, toIndex }A row was dragged to a new position.
pageChange{ page, pageSize, pageCount }The page or page size changed.
rowsLoaded / rowsLoadFailed{ start, end, total? } / { start, end, error }A server block arrived or failed.
pivotChange{ pivot }Pivot mode was turned on, changed or turned off.
focusChange{ rowIndex, colId }The focused cell moved.
beforeSort / beforeFilter / beforePageChange{ sort | colId, model | page, pageSize, cancel() }Fired before the change; call cancel() to stop it (for example to sort or filter on your server instead).
beforeEdit / beforeCellChange{ row, rowIndex, colId, oldValue?, newValue?, cancel() }Fired before an editor opens or a value is written (edit, paste, fill, delete); cancel() stops it.
rowDrop{ row, target, position, fromOtherGrid, fromGrid }A row was dropped on this grid, also from another grid of the same drag group.
scroll{ top, left }The rows area scrolled.
childrenLoaded / childrenLoadFailed{ row, rows } / { row, error }treeData.loadChildren finished or failed for a row.
transactionApplied{ added, updated, removed, notFound }applyTransaction (or a batch of applyTransactionAsync) finished.
conditionalFormatsChange{ formats }The conditional formats changed (API or the dialog).
assistantAnswer{ prompt, message, applied, skipped }The assistant panel got an answer and applied its actions.
rowEditStart / rowEditStop{ row, rowIndex } / { row, rowIndex, committed, changes }editType 'row': a row started or finished editing; changes lists the changed cells.
advancedFilterChange{ advancedFilter }The advanced filter changed.
columnGroupOpened{ groupId, open }A collapsible column group was opened or closed.

Questions about this page

How do I listen to grid events?

Call grid.on("cellClick", handler); it returns a function that stops listening. The wrappers use the same events as onCellClick (React), @cell-click (Vue) and (cellClick) (Angular).

Can I stop a sort or an edit before it happens?

Yes. beforeSort, beforeFilter, beforePageChange, beforeEdit and beforeCellChange arrive first; call cancel() to stop the change.