Skip to main content

DomainFrameEditor

Defined in: js-api/src/ui/domains/domains-editor.ts:279

THE single writer of a domain frame's editing state.

It wraps a DataFrame produced by table.queryDf(...) and attaches three invisible service columns — DomainFrameEditor.STATE_COLUMN, DomainFrameEditor.CHANGES_COLUMN, DomainFrameEditor.ERRORS_COLUMN — that hold everything about the pending batch: which rows are new/modified/deleted, the ORIGINAL value of every changed cell, and the per-cell validation errors. Grids, forms and the save pipeline all read that one state; nothing keeps a parallel store.

const editor = await DomainFrameEditor.create(grok.dapi.domains.table('grit.issue'));
editor.setValue(0, 'title', 'New title'); // tracked, validated, highlighted
await editor.save(); // ONE /transaction

Every service column is tagged out of binary AND csv export, so the state is memory-only: a saved project, toByteArray(), toCsv(), an export or a batch() upload built from the frame never carry it.

Writing. Go through setValue (programmatic) or beginEdit + commitEdit (an in-grid edit, where the grid has already written the cell). Writing a cell directly on the DataFrame bypasses the tracking and the value is silently NOT saved.

Deleted rows stay in the frame and are hidden by ANDing them out of the filter bitset on every filter recomputation, so undoing a delete (unmarkDeleted) is trivial and row order never moves.

Refreshing discards edits — BY DESIGN. refresh re-runs the query and rebuilds the frame and its state from scratch; there is no merge and never will be. Deciding whether it is safe to refresh is the CALLER's job: read isDirty / subscribe to onDirtyChanged and prompt (save / discard / cancel) before calling it. A component that refreshes on a timer or on a route change without that check WILL eat a user's batch edits.

Properties

PropertyModifierTypeDefault valueDescriptionDefined in
capabilitiesreadonlyDomainTableCapabilitiesundefinedEffective capabilities of the current user, SNAPSHOT when the editor was created — what read-only degradation and the writable-column payload filter derive from. A later grok.dapi.domains.invalidateUiCaches() (or a grant change) does NOT reach an existing editor: re-create it to pick the new permissions up.js-api/src/ui/domains/domains-editor.ts:334
clientreadonlyDomainTableClientundefinedThe table the frame's rows belong to.js-api/src/ui/domains/domains-editor.ts:328
CHANGES_COLUMNreadonly"~changes"'~changes'JSON column holding the ORIGINAL values of changed cells only (sparse).js-api/src/ui/domains/domains-editor.ts:283
ERRORS_COLUMNreadonly"~errors"'~errors'JSON column holding per-cell DomainCellErrors.js-api/src/ui/domains/domains-editor.ts:285
SERVICE_COLUMNSreadonlyreadonly string[]undefinedThe three service columns an editor attaches — every one of them tagged out of binary AND csv export, so the editing state can never reach a saved project, an export, an upload, or a batch() fed from the frame.js-api/src/ui/domains/domains-editor.ts:290
STATE_COLUMNreadonly"~state"'~state'Row state column: `'''new'

Accessors

changeCount

Get Signature

get changeCount(): number

Defined in: js-api/src/ui/domains/domains-editor.ts:481

Number of pending cell changes — what a "N unsaved changes" bar shows.

Returns

number


dataFrame

Get Signature

get dataFrame(): DataFrame

Defined in: js-api/src/ui/domains/domains-editor.ts:462

The frame being edited. It is REPLACED by refresh — re-read it (or subscribe to onRefreshed) instead of caching it.

Returns

DataFrame


errorCount

Get Signature

get errorCount(): number

Defined in: js-api/src/ui/domains/domains-editor.ts:695

Number of cells whose problem blocks save.

Returns

number


isDirty

Get Signature

get isDirty(): boolean

Defined in: js-api/src/ui/domains/domains-editor.ts:474

Whether anything is pending (a changed cell, a new row, a deleted row).

Returns

boolean


isSaving

Get Signature

get isSaving(): boolean

Defined in: js-api/src/ui/domains/domains-editor.ts:478

Whether a save is in flight. While it is, the editor refuses every write, discard and refresh — see save.

Returns

boolean


onChanged

Get Signature

get onChanged(): Observable<DomainFrameEditor>

Defined in: js-api/src/ui/domains/domains-editor.ts:484

Fires on every service-state write — the repaint hook for a grid.

Returns

Observable<DomainFrameEditor>


onConflict

Get Signature

get onConflict(): Observable<DomainVersionConflictError>

Defined in: js-api/src/ui/domains/domains-editor.ts:492

Fires when a save hits a version conflict, BEFORE the standard dialog.

Returns

Observable<DomainVersionConflictError>


onDirtyChanged

Get Signature

get onDirtyChanged(): Observable<boolean>

Defined in: js-api/src/ui/domains/domains-editor.ts:486

Fires when isDirty flips — what a caller's refresh policy listens to.

Returns

Observable<boolean>


onRefreshed

Get Signature

get onRefreshed(): Observable<DataFrame>

Defined in: js-api/src/ui/domains/domains-editor.ts:494

Fires with the NEW frame after refresh rebuilt it.

Returns

Observable<DataFrame>


onSaved

Get Signature

get onSaved(): Observable<DomainSaveResult>

Defined in: js-api/src/ui/domains/domains-editor.ts:490

Fires after a successful save.

Returns

Observable<DomainSaveResult>


onSavingChanged

Get Signature

get onSavingChanged(): Observable<boolean>

Defined in: js-api/src/ui/domains/domains-editor.ts:488

Fires when isSaving flips — what a grid locks its editing on.

Returns

Observable<boolean>


properties

Get Signature

get properties(): Property[]

Defined in: js-api/src/ui/domains/domains-editor.ts:468

Registry Property metadata of the table's declared columns.

Returns

Property[]


query

Get Signature

get query(): DomainQuerySpec<string, string> | undefined

Defined in: js-api/src/ui/domains/domains-editor.ts:471

The query refresh re-runs.

Returns

DomainQuerySpec<string, string> | undefined


table

Get Signature

get table(): string

Defined in: js-api/src/ui/domains/domains-editor.ts:465

'<schema>.<table>'.

Returns

string

Methods

addRow()

addRow(values?, options?): number

Defined in: js-api/src/ui/domains/domains-editor.ts:587

Appends a new, unsaved row (state 'new'), optionally prefilled; returns its index (-1 when refused because a save is in flight).

options.pristine adds it as a row nobody has written to YET: it is part of the batch a save writes, but it contributes NOTHING to changeCount / isDirty until the first setValue or commitEdit — the "pristine until touched" contract of an insert form, whose untouched (however prefilled) row must not arm the unsaved-changes gate. A row added by a USER gesture (the grid's Add row) is pending immediately, which is the default.

Parameters

ParameterType
values?{[column: string]: any; }
options?{ pristine?: boolean; }
options.pristine?boolean

Returns

number


beginEdit()

beginEdit(row): void

Defined in: js-api/src/ui/domains/domains-editor.ts:533

Snapshots [row]'s current values so a following commitEdit knows what the cell held BEFORE the edit. A grid calls this when the cell becomes current — an edit can only start there. Without a snapshot the edit is still tracked and saved, it just cannot be reverted.

Parameters

ParameterType
rownumber

Returns

void


buildOps()

buildOps(): DomainPendingOp[]

Defined in: js-api/src/ui/domains/domains-editor.ts:719

The pending batch as transaction ops, in row order: 'new' rows insert their writable values, 'modified' rows update ONLY their changed columns with the row's expectedVersion, 'deleted' rows delete. Exposed so a caller can inspect or extend the payload (a master-detail save appends its own ops to one transaction).

An empty cell of a NEW row is LEFT OUT of the insert rather than sent as an explicit null, so the column takes its server-side default; a column with no default and no value is rejected by the server's own nullability check (and by validate before that). Clearing a cell of a MODIFIED row does send null — that is an edit, not an omission.

Returns

DomainPendingOp[]


changesOf()

changesOf(row): object

Defined in: js-api/src/ui/domains/domains-editor.ts:507

ORIGINAL values of [row]'s changed cells, keyed by column (empty when the row is unchanged; always empty for a 'new' row — all of its values are new). Read-only: the object is the editor's own cached parse, and writing to it changes nothing on the frame.

Parameters

ParameterType
rownumber

Returns

object


clearSnapshots()

clearSnapshots(): void

Defined in: js-api/src/ui/domains/domains-editor.ts:550

Drops the beginEdit snapshots. A HOST that rewrites row values IN PLACE (a re-query refreshing the same frame object, with no row-count change and no frame event) MUST call this afterwards: the snapshots are keyed by row index and would otherwise record the OLD rows' values as edit originals (STATE-CONTRACT H8).

Returns

void


commitEdit()

commitEdit(row, column): void

Defined in: js-api/src/ui/domains/domains-editor.ts:567

Tracks a cell the GRID already wrote (its onCellValueEdited path); the original comes from the beginEdit snapshot.

Parameters

ParameterType
rownumber
columnstring

Returns

void


detach()

detach(): void

Defined in: js-api/src/ui/domains/domains-editor.ts:843

Releases the frame subscriptions. The service columns stay on the frame — drop the frame, or remove them, if it outlives the editor.

Returns

void


discard()

discard(): void

Defined in: js-api/src/ui/domains/domains-editor.ts:658

Drops the whole pending batch: changed cells go back to their originals, new rows are removed, deleted rows are restored. Refused while a save is in flight — removing rows under the transaction would make its results land on the wrong ones.

Returns

void


errorOf()

errorOf(row, column): DomainCellError | null

Defined in: js-api/src/ui/domains/domains-editor.ts:523

The cell's problem, or null.

Parameters

ParameterType
rownumber
columnstring

Returns

DomainCellError | null


errorsOf()

errorsOf(row): object

Defined in: js-api/src/ui/domains/domains-editor.ts:513

Per-cell problems of [row], keyed by column. Read-only, see changesOf.

Parameters

ParameterType
rownumber

Returns

object


isChanged()

isChanged(row, column): boolean

Defined in: js-api/src/ui/domains/domains-editor.ts:518

Whether the cell carries a pending change (what highlighting keys on).

Parameters

ParameterType
rownumber
columnstring

Returns

boolean


markDeleted()

markDeleted(rows): void

Defined in: js-api/src/ui/domains/domains-editor.ts:614

Marks rows deleted: they stay in the frame (order untouched) and are excluded from the filter until save removes them for real.

Parameters

ParameterType
rowsnumber | number[]

Returns

void


refresh()

refresh(query?): Promise<DataFrame>

Defined in: js-api/src/ui/domains/domains-editor.ts:827

Rebuilds the frame from the server: re-runs [query] (the attached one by default) and re-attaches the service columns from scratch.

Pending edits do NOT survive this — by design. There is no merge: the control is refresh-agnostic and this method never reconciles old and new state. Deciding WHETHER to refresh while edits are pending is the caller's responsibility — check isDirty (or subscribe to onDirtyChanged) and prompt the user to save or discard first.

Resolves to the NEW frame, which also arrives on onRefreshed: a grid bound to the old one must rebind. Refused (resolving to the CURRENT frame, with a warning) while a save is in flight — the resolved value alone does not tell a refusal from a rebuild, so check isSaving first (or compare the frame identity) when it matters.

Parameters

ParameterType
query?DomainQuerySpec<string, string>

Returns

Promise<DataFrame>


revertCell()

revertCell(row, column): void

Defined in: js-api/src/ui/domains/domains-editor.ts:627

Restores one cell to its original value and drops its change entry. Refused while a save is in flight.

Parameters

ParameterType
rownumber
columnstring

Returns

void


revertRow()

revertRow(row): void

Defined in: js-api/src/ui/domains/domains-editor.ts:647

revertCell for every changed cell of [row].

Parameters

ParameterType
rownumber

Returns

void


save()

save(): Promise<boolean>

Defined in: js-api/src/ui/domains/domains-editor.ts:774

Writes the whole pending batch as ONE /transaction: audit rows share a tx_id, and any failure rolls every op back. Resolves to whether the batch landed.

Blocking cell errors refuse the save (naming the first one). A version conflict goes through the platform's standard reload/overwrite dialog and the chosen outcome is applied and retried. Server validation errors land on the offending cells as DomainFrameEditor.ERRORS_COLUMN entries and everything stays pending.

The editor is CLOSED while this runs (isSaving): every write, discard and refresh is refused with a warning instead of being silently lost between the request and its results (and, for the row-removing ones, instead of shifting the rows the results address). A grid bound to the editor locks its own editing off onSavingChanged.

Returns

Promise<boolean>


setValue()

setValue(row, column, value): void

Defined in: js-api/src/ui/domains/domains-editor.ts:557

Writes [value] into the cell AND tracks it — the programmatic write path (a form field, a paste, a fill-down). Refused while a save is in flight.

Parameters

ParameterType
rownumber
columnstring
valueany

Returns

void


stateOf()

stateOf(row): DomainRowState

Defined in: js-api/src/ui/domains/domains-editor.ts:499

Editing state of [row].

Parameters

ParameterType
rownumber

Returns

DomainRowState


unmarkDeleted()

unmarkDeleted(rows): void

Defined in: js-api/src/ui/domains/domains-editor.ts:621

Undoes markDeleted, restoring whatever the row was before — a row added in this batch goes back to 'new', an edited one back to 'modified'.

Parameters

ParameterType
rowsnumber | number[]

Returns

void


validate()

validate(): number

Defined in: js-api/src/ui/domains/domains-editor.ts:684

Re-runs every cell validator over the pending batch; returns the number of blocking (kind: 'error') cells. Call it before offering Save when values arrived from outside setValue. Refused (reporting the CURRENT count) while a save is in flight — it writes the state columns like every other mutator.

Returns

number


attach()

static attach(dataFrame, client, options?): Promise<DomainFrameEditor>

Defined in: js-api/src/ui/domains/domains-editor.ts:349

Attaches the editing state to an EXISTING frame of [client]'s rows (a queryDf result). Pass options.query so refresh knows what to re-run.

Parameters

ParameterType
dataFrameDataFrame
clientDomainTableClient
options?DomainFrameEditorOptions

Returns

Promise<DomainFrameEditor>


attachTo()

static attachTo(dataFrame, schema, table, options?): Promise<DomainFrameEditor>

Defined in: js-api/src/ui/domains/domains-editor.ts:364

attach for a host that has a frame and a table address but no client of its own — the entry point of the Dart Domain View's grid mode, which owns its frame and hands it over to be edited.

Parameters

ParameterType
dataFrameDataFrame
schemastring
tablestring
options?DomainFrameEditorOptions

Returns

Promise<DomainFrameEditor>


create()

static create(client, options?): Promise<DomainFrameEditor>

Defined in: js-api/src/ui/domains/domains-editor.ts:372

Runs options.query (everything the caller may see, by default) and attaches to the resulting frame.

Parameters

ParameterType
clientDomainTableClient
options?DomainFrameEditorOptions

Returns

Promise<DomainFrameEditor>


editorsOf()

static editorsOf(widget): DomainFrameEditor[]

Defined in: js-api/src/ui/domains/domains-editor.ts:455

The editors [widget] answers for, or none — the duck-typed read of IEditorHost a container uses on children of any class.

Parameters

ParameterType
widgetany

Returns

DomainFrameEditor[]


forContext()

static forContext(context, options?): DomainFrameEditor

Defined in: js-api/src/ui/domains/domains-editor.ts:385

SYNCHRONOUS: an editor over an EMPTY frame of [context]'s declared columns — everything attach awaits is already in the prefetched context, so a widget factory can build its editor without a round trip and load the rows afterwards (refresh, which replaces the frame and fires onRefreshed).

Parameters

ParameterType
contextIDomainTableContext
options?DomainFrameEditorOptions

Returns

DomainFrameEditor


forRows()

static forRows(client, values, options?): Promise<DomainFrameEditor>

Defined in: js-api/src/ui/domains/domains-editor.ts:408

Builds an editor over rows that do NOT come from the server: a frame is built locally from the table's declared columns and every entry of [values] is added as a 'new' row — the INSERT path of a form (domains.table(...).form({values})), with no query round trip.

The added rows are PRISTINE: an unsaved row the user has not written to yet is not a pending change (see addRow), so an untouched New form has nothing to prompt about.

Everything else is identical to create: the same single-writer model, the same service columns and export tags, the same validation, and a save that writes the batch as one transaction. refresh has nothing to re-run unless options.query says otherwise — and re-running it would replace these rows, which is why a form never refreshes.

Parameters

ParameterType
clientDomainTableClient
valuesobject[]
options?DomainFrameEditorOptions

Returns

Promise<DomainFrameEditor>


isReferenceProperty()

static isReferenceProperty(p): boolean

Defined in: js-api/src/ui/domains/domains-editor.ts:448

Whether [p] addresses another row rather than carrying a value of its own — a ref column (semType '<schema>.<table>') or a user/group column. Those hold uuids: a picker is their editing path, not a text cell.

Parameters

ParameterType
pProperty

Returns

boolean


validateCellValue()

static validateCellValue(p, value): string | null

Defined in: js-api/src/ui/domains/domains-editor.ts:427

Validates one cell value against its registry Property — the same constraints the server re-runs on write, producing the server's exact message texts so an inline marker and a rejected save read identically.

Numeric properties take a dart2js-safe path (under dart2js every whole number is double, which would reject every integer), and string_list values are left to the server, which coerces them. Returns null when the value is fine.

Parameters

ParameterType
pProperty
valueany

Returns

string | null