Changes on server rows
With a datasource, applyTransaction updates loaded rows in place with a flash, and adds or removes reload the loaded blocks while the old rows stay on screen; refreshRows({ keepRows }) does it by hand.
Live demoServer row changes
Update, add and remove rows of a slow fake server.
Code for this demo
import { createGrid, type ColumnDef, type Row } from '@freegridjs/core';
import { makeRows } from '../data';
import { button, separator, text, tr, type DemoContext } from '../ui';
export default function mount(ctx: DemoContext) {
const h = (en: string, ko: string) => tr(ctx.lang, { en, ko });
// a fake server of 10,000 rows that answers in 600 ms
let rows: Row[] = makeRows(10_000);
const grid = createGrid(ctx.host, {
columns: [{ field: 'id', header: 'ID', type: 'number', width: 80 }, { field: 'name', header: h('Name', '이름'), width: 170 }, { field: 'status', header: h('Status', '상태'), width: 120 }, { field: 'q1', header: h('Q1', '1분기'), type: 'number', format: '#,##0', width: 120 }],
locale: ctx.lang, getRowId: r => String(r.id), blockSize: 100,
datasource: { getRows: p => new Promise(res => setTimeout(() => res({ rows: rows.slice(p.start, p.end).map(r => ({ ...r })), total: rows.length }), 600)) },
});
grid.on('transactionApplied', e => ctx.log(`added ${e.added.length}, updated ${e.updated.length}, removed ${e.removed.length}, notFound ${e.notFound.length}`));
button(ctx, h('Server changes row 2', '서버에서 2행 변경'), () => {
const r = rows.find(x => x.id === 2)!;
r.status = r.status === 'Active' ? 'Pending' : 'Active';
r.q1 = Math.round(Math.random() * 100000);
grid.applyTransaction({ update: [{ ...r }] });
});
button(ctx, h('Server deletes the first row', '서버에서 첫 행 삭제'), () => {
const gone = rows.shift()!;
grid.applyTransaction({ remove: [{ id: gone.id }] });
});
button(ctx, h('Server adds a row at the top', '서버에서 맨 위에 행 추가'), () => {
const r = { ...rows[0], id: 100000 + rows.length, name: h('New customer', '새 고객') };
rows = [r, ...rows];
grid.applyTransaction({ add: [r] });
});
button(ctx, h('Reload, keep rows', '행 유지하며 다시 받기'), () => grid.refreshRows({ keepRows: true }));
text(ctx, h('Updates change in place with a flash. Deletes and adds reload the loaded blocks; the old rows stay until the answer (0.6 s).',
'수정은 그 자리에서 깜빡이며 바뀝니다. 삭제·추가는 불러온 블록을 다시 받고, 답(0.6초)이 올 때까지 기존 행이 그대로 보입니다.'));
return grid;
}With a datasource the server owns the rows; the grid only holds the blocks it has loaded. When something changes on the server — someone else edited a row, your own save finished, a push message arrived — tell the grid with applyTransaction.
What each part does
| Transaction | With a datasource |
|---|---|
| update | Fields are copied onto the loaded row with the same id (getRowId); the changed cells flash. Rows that are not loaded are listed in notFound — they will come right when their block is loaded. |
| upsert | Updates loaded rows; if some were not found, the loaded blocks are asked for again (they may be new). |
| add / remove | Happened on the server already: the grid asks again for the blocks it has loaded and swaps them in when they arrive. Until then the old rows stay on screen — no loading rows, no jump. |
const grid = createGrid(el, {
columns,
getRowId: row => String(row.id), // needed to find rows by id
datasource: { getRows: params => fetch('/api/orders?' + toQuery(params)).then(r => r.json()) },
});
// a websocket says order 42 changed
socket.on('order', o => grid.applyTransaction({ update: [o] }));
// your own delete finished on the server
await fetch('/api/orders/7', { method: 'DELETE' });
grid.applyTransaction({ remove: [{ id: 7 }] }); // the loaded blocks reload; rows stay until then
// after a bulk import: the same by hand
grid.refreshRows({ keepRows: true });refreshRows
| Call | Does |
|---|---|
| refreshRows() | Forgets every row and loads from the start of the view; rows show as loading meanwhile |
| refreshRows({ keepRows: true }) | Asks again only for the loaded blocks and keeps them on screen until the answers come |
Details
- The result is
{ added, updated, removed, notFound }andtransactionAppliedfires, as without a datasource. - An edit open in a reloaded row is saved first.
- Transactions are not undoable and do not count as user edits (
getModifiedRows), like live updates without a datasource. setData,addRows,removeRowsand row moves stay client-only: change the server, then send a transaction or call refreshRows.- Users can still edit cells of loaded rows; save them with
cellValueChangedorgetModifiedRows().
Questions about this page
How do I update one row in infinite scroll without reloading everything?
Call applyTransaction({ update: [changedRow] }) with a getRowId on the grid. The loaded row with that id changes in place and flashes; nothing is fetched.