Chapter 31 of 34
Inline editing
Change quantity and status right in the table – and recalculate what depends on them.
After this chapter you can
- make a column editable
- convert input with editInputPipe
- use a select editor
- react to changes
Make columns editable
Editing is switched on per column. Three fields of the ColumnDefIf matter:
import { type ColumnDefIf, SelectCellRenderer, TrueFn, ValueLabel, editInputPipeForNumber } from "@guiexpert/table";import type { Order } from "./data/orders";
export function applyOrderEditing(columns: ColumnDefIf[]): void { const column = (property: keyof Order) => columns.find(c => c.property === property)!;
const quantity = column("quantity"); quantity.editable = TrueFn; quantity.editInputPipe = editInputPipeForNumber; // the input text becomes a number
const status = column("status"); status.editable = TrueFn; status.getEditRenderer = () => new SelectCellRenderer( // a <select> instead of a text input ["open", "paid", "shipped", "cancelled"].map(s => new ValueLabel(s, s)));}
/** After an edit: recalculate the derived value. */export function recalcOrder(order: Order): void { order.total = Math.round(order.quantity * order.price * 100) / 100;}editable– a function, may depend on the row (() => !locked).editInputPipe– converts the text of the input field before it is written into the model:editInputPipeForNumberturns"12"into12.getEditRenderer– the editor. Default: a text input (InputCellRenderer); here aSelectCellRendererwithValueLabeloptions.
Start editing: double-click a cell, or press F2 on the focused cell. The value is taken over when the editor fires
its change event – Enter or leaving the field for a text input, picking an option for a select.
After the edit
The table writes the new value into your object (via AreaModelIf.setValue()) and reports it:
EventListenerIf.onModelChanged() with a GeModelChangeEvent. Derived values are your job:
import { EventAdapter, type GeModelChangeEvent } from "@guiexpert/table";
class EditEvents extends EventAdapter { constructor(private readonly onEdited: (rowIndex: number, columnIndex: number) => void) { super(); } override onModelChanged(evt: GeModelChangeEvent): void { // after every edit for (const cell of evt.cells) this.onEdited(cell.rowIndex, cell.columnIndex); }}const events = new EditEvents((row, col) => { const order = tableModel.getBodyModel().getRowByIndex(row) as Order; recalcOrder(order); // total = quantity × price (tableModel.getAreaModel("footer") as OrderTotalsFooterModel).invalidate(); // footer: sum again tableApi.repaint();});const tableScope = new TableScope(host, tableModel, new SimpleDomService(), options, events);tableScope.firstInit();const tableApi = tableScope.getApi();
Saving
The table has no notion of a backend. Send the change from onModelChanged – the event contains row and column,
the new value is already in your object – and, if the server rejects it, write the old value back and repaint.
Next
Not the user changes the values, the market does: chapter 32 (Live data).