Hypergrid 3 data models have a minimal required interface, as outlined on the Data Model API wiki page.
TL;DR
The minimum interface is an object with just three methods: getRowCount()
getSchema()
and getValue(x, y)
.
Methods
addListener(handler)
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
If your data model does not implement this method, Local#resetDataModel
adds the default implementation from polyfills.js. If your data model does implement it, it should also implement the sister methods dispatchEvent
, removeListener
, and removeAllListeners
, because they all work together and you don't want to mix native implementations with polyfills.
Hypergrid calls this method subscribe to data model events. The data model calls its own implementation of dispatchEvent
to publish events to subscribers.
Both the addListener
polyfill as well as datasaur-base
's implementation service multiple listeners for the use case of multiple grid instances all using the same data model instance. To support this use case, your data model should service multiple listeners as well. (Doing so also lets the application add its own listener(s) to the data model.)
Parameters:
Name | Type | Description |
---|---|---|
handler |
DataModelListener | A reference to a function bound to a grid instance. The function is called whenever the data model calls its |
addRow(yopt, dataRow)
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Insert or append a new row.
Parameters:
Parameters:
Name | Type | Attributes | Default | Description |
---|---|---|---|---|
y |
number |
<optional> |
Infinity | The index of the new row. If |
dataRow |
object |
apply()
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Transforms the data. All the rows are subject to change, including the row count.
DataModelError() → {Array.<dataRowObject>}
A direct descendent of Error
.
Returns:
- Type
- Array.<dataRowObject>
delRow(y, rowCountopt) → {Array.<dataRowObject>}
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Rows are removed entirely and no longer render.
Indexes of all remaining rows are decreased by rowCount
.
Parameters:
Parameters:
Name | Type | Attributes | Default | Description |
---|---|---|---|---|
y |
number | |||
rowCount |
number |
<optional> |
1 |
Returns:
- Type
- Array.<dataRowObject>
dispatchEvent(event)
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
If your data model does not implement this method, Local#resetDataModel
adds the default implementation from polyfills.js. If your data model does implement it, it should also implement the sister methods addListener
, removeListener
, and removeAllListeners
, because they all work together and you don't want to mix native implementations with polyfills.
If addListener
is not implemented, Hypergrid falls back to a simpler approach, injecting its own implementation of dispatchEvent
, bound to the grid instance, into the data model. If the data model already has such an implementation, the assumption is that it was injected by another grid instance using the same data model. The newly injected implementation will call the original injected implementation, thus creating a chain. This is an inferior approach because grids cannot easily unsubscribe themselves. Applications can remove all subscribers in the chain by deleting the implementation of dispatchEvent
(the end of the chain) from the data model.
Parameters:
Parameters:
Name | Type | Description |
---|---|---|
event |
DataModelEvent |
drillDownCharMap() → {Array.<dataRowObject>}
Characters that can be used to construct cell values representing drill downs in a tree structure.
A specialized cell renderer is often employed to produce better results using graphics instead of characters.
Returns:
- Type
- Array.<dataRowObject>
fetchData(rectangles) → {function}
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Tells dataModel what cells will be needed by subsequent calls to getValue()
. This helps remote or virtualized data models fetch and cache data. If your data model doesn't need to know this, don't implement it.
Parameters:
Parameters:
Name | Type | Description |
---|---|---|
rectangles |
Array.<Rectangle> | Unordered list of rectangular regions of cells to fetch in a single (atomic) operation. |
Returns:
[callback] - Optional callback. If provided, implementation calls it with false
on success (requested data fully fetched) or true
on failure.
- Type
- function
getCell(config, rendererName) → {CellRenderer}
Renderer configuration interceptor.
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
If your data model does not implement this method, Local#resetDataModel
adds the default implementation (module:hooks.getCell
).
Description
This method is a hook called on every cell just prior to rendering and is intended to be overridden.
The first parameter to this method, config
, Please refer to the renderConfig
object for details. Most of the properties on this object can be overridden programmatically in this method. Properties typically overridden include renderer
, editor
, format
, and the various permutations of font
, color
, and halign
.
Your override will be called with the data model as it's execution context (the this
value).
The only requirement for this method (or its override) is to return a reference to an instantiated cell renderer, which is all the default implementation does. This is typically the renderer whose name is in the config.renderer
, property (assumed to be a "registered" cell renderer). It doesn't have to be that cell renderer, however; and any object with a paint
method will do.
IMPORTANT CAVEAT!!
Although this hook was designed to be overridden, adding lots (or any, really) programmatic logic to be executed on every cell, on every render, is expensive in terms of performance, and doing so should only be a last resort.
As Hypergrid has evolved, many properties have been added including row and cell properties, which can accomplish much that was previously impossible without overrideing getCell
. For example, you can now select a formatter and a renderer simply by setting a column's (or row's) (or cell's) format
or renderer
property.
Overriding getCell
still has great facility when the rendering needs to be a function of the data values, but other than that, every effort should be made to avoid overriding getCell
whenever possible.
Parameters:
Parameters:
Name | Type | Description |
---|---|---|
config |
CellEditor#renderConfig | |
rendererName |
string | Same as |
Returns:
An instantiated cell renderer.
- Type
- CellRenderer
getCellEditorAt(columnIndex, rowIndex, editorName, cellEvent) → {undefined|CellEditor}
Instantiate a new cell editor.
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
If your data model does not implement this method, Local#resetDataModel
adds the default implementation (module:hooks.getCellEditorAt
).
Description
The application developer may override this method to:
- Instantiate and return an arbitrary cell editor. The generic implementation here simply returns the declared cell editor. This is
undefined
when there was no such declaration, or if the named cell editor was not registered. - Return
undefined
for no cell editor at all. The cell will not be editable. - Set properties on the instance by passing them in the
options
object. These are applied to the new cell editor object after instantiation but before rendering. - Manipulate the cell editor object (including its DOM elements) after rendering but before DOM insertion.
Overriding this method with a null function (that always returns undefined
) will have the effect of making all cells uneditable.
The only requirement for this method (or its override) is to return a reference to an instantiated cell editor, which is all the default implementation does. This is typically the cell editor whose name is in the config.editor
property (assumed to be a "registered" cell editor). It doesn't have to be that cell editor, however; any object conforming to the CellEditor interface will do.
Parameters:
Parameters:
Name | Type | Description |
---|---|---|
columnIndex |
number | Absolute column index. I.e., the position of the column in the data source's original |
rowIndex |
number | Row index of the data row in the current list of rows, regardless of vertical scroll position, offset by the number of header rows (all the rows above the first data row including the filter row). I.e., after subtracting out the number of header rows, this is the position of the data row in the |
editorName |
string | The proposed cell editor name (from the render properties). |
cellEvent |
CellEvent | All enumerable properties of this object will be copied to the new cell editor object for two purposes:
Developer's override of this method may add custom properties, for the purposes listed above. Hypergrid adds the following properties, required by
|
Returns:
An object instantiated from the registered cell editor constructor named in editorName
. A falsy return means the cell is not editable because the editorName
was not registered.
- Type
- undefined | CellEditor
getColumnCount() → {number}
Same as getSchema().length
.
Returns:
Number of columns in the schema.
- Type
- number
getData(metadataFieldNameopt) → {Array.<dataRowObject>}
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
All grid data.
Parameters:
Parameters:
Name | Type | Attributes | Description |
---|---|---|---|
metadataFieldName |
string |
<optional> |
If provided, the output will include the row metadata object in a "hidden" field with this name. |
Returns:
All the grid's data rows.
- Type
- Array.<dataRowObject>
getDataIndex(y) → {number}
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Synonym for getRowIndex.
Parameters:
Parameters:
Name | Type | Description |
---|---|---|
y |
number | Transformed data row index. |
Returns:
Untransformed data row index.
- Type
- number
getMetadataStore()
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Get the metadata store. The precise type of this object is implementation-dependent so not defined here.
datasaur-base
supplies fallback implementations of this method as well as DataModel#setMetadataStore
which merely get and set this.metadata
in support of DataModel#getRowMetadata
and DataModel#setRowMetadata
.
Custom data models are not required to implement them if they don't need them.
Hypergrid never calls getMetadataStore
itself. If implemented, Hypergrid does make a single call to setMetadataStore
when data model is reset (see Local#resetDataModel
) with no arguments.
Returns:
Metadata store object.
getRow(rowIndex) → {number|undefined}
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Get a row of data.
The injected default implementation is an object of lazy getters.
Parameters:
Parameters:
Name | Type | Description |
---|---|---|
rowIndex |
number |
Returns:
The data row corresponding to the given rowIndex
; or undefined
if no such row.
- Type
- number | undefined
getRowCount() → {number}
Returns:
The number of data rows currently contained in the model.
- Type
- number
getRowIndex(y) → {number}
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Only called by Hypergrid when it receives the data-prereindex
or data-postreindex
events.
These events are typically triggered before and after data model remaps the rows (in its apply
method).
Parameters:
Parameters:
Name | Type | Description |
---|---|---|
y |
number | Transformed data row index. |
Returns:
Untransformed data row index.
- Type
- number
getRowMetadata(y, prototypeopt) → {undefined|false|object}
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Get the row's metadata object, which is a hash of cell properties objects, for those cells that have property overrides, keyed by column name; plus a row properties object with key __ROW
when there are row properties.
The default implementations of getRowMetadata
and setRowMetadata
store the metadata in an in-memory table. If this is not appropriate, override these methods to store the meta somewhere else (e.g., with the data in a hidden column, in another database table, in local storage, etc.).
Parameters:
Parameters:
Name | Type | Attributes | Description |
---|---|---|---|
y |
number | Row index. |
|
prototype |
object |
<optional> |
When row found but no metadata found, set the row's metadata to new object created from this object when defined.
Typical defined value is |
Returns:
One of:
- object - existing metadata object or new metadata object created from
prototype
; else false
- row found but no existing metadata andprototype
was not defined; elseundefined
- no such row
- Type
- undefined | false | object
getSchema() → {Array.<columnSchema>}
Get list of columns. The order of the columns in the list defines the column indexes.
On initial call and again whenever the schema changes, the data model must dispatch the fin-hypergrid-schema-loaded
event, which tells Hypergrid to decorate
the schema and recreate the column objects.
Returns:
- Type
- Array.<columnSchema>
getValue(columnIndex, rowIndex) → {string|number|boolean|null}
Get a cell's value given its column & row indexes.
Parameters:
Parameters:
Name | Type | Description |
---|---|---|
columnIndex |
number | |
rowIndex |
number |
Returns:
The member with the given columnIndex
from the data row with the given rowIndex
.
- Type
- string | number | boolean | null
install(api, options)
Install methods into data model.
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
If your data model does not implement this method, Local#resetDataModel
adds the default implementation from polyfills.js and then uses it to install the other polyfills and fallbacks when no native implementations exist, thus ensuring there are implementations for Hypergrid to call.
Catcher functions
Catcher functions catch calls made by Hypergrid to otherwise unimplemented functions so such calls fail silently rather than throw an error.
- When
api
is array:install
injects catcher functions named for each string in the array. - When
api
is an object:install
injects catcher functions named for each key in the object. (Keys with non-function values are excluded.)
Keys constructor
and initialize
are always excluded. In addition, the install
method defined in datasaur-base
will also exclude keys missing from whitelist (api['!!keys']
) or included in blacklist (api['!key']
).
The type of catcher function depends on the data model:
- Flat data model: Catcher functions are simple no-ops that fail silently.
- Stacked data model: Catcher functions forward calls down the stack to the first native implementation found. When no native implementation is found, the call then fails silently.
Fallbacks methods
Instead of failing silently, Hypergrid can instead install fallback methods for missing implementations:
When options.inject
is truthy (and api
is an object), install
injects api
's fallback methods into the data model instead of simple catchers when no native implementation already exists (however see options.force
below).
For a stacked data model, the target for the injection is the bottom instance in the stack (the data source instance); and the forwarding mechanism is also installed so the call will find the fallback there.
Forced installation
When options.force
is truthy, the fallback methods are always installed regardless of whether or not a native implementation exists; i.e., the fallbacks override the native implementations.
Parameters:
Name | Type | Attributes | Description |
---|---|---|---|
api |
object | Array.<string> | Collection of methods or a list of method names. The following keys are however ignored:
|
|
options |
object | ||
options.inject |
boolean |
<optional> |
Injects |
options.force |
boolean |
<optional> |
If |
isTree() → {boolean}
IMPLEMENTATION OF THIS METHOD IS OPTIONAL. It is only required for data models that support tree views.
Returns:
The grid view is a tree (presumably has a tree column).
- Type
- boolean
isTreeCol(columnIndex) → {boolean}
IMPLEMENTATION OF THIS METHOD IS OPTIONAL. It is only required for data models that support tree views.
Parameters:
Parameters:
Name | Type | Description |
---|---|---|
columnIndex |
number |
Returns:
This column is the tree column (displays tree structure; may or may not be an interactive drill-down control).
- Type
- boolean
removeAllListeners()
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
If your data model does not implement this method, Local#resetDataModel
adds the default implementation from polyfills.js. If your data model does implement it, it should also implement the sister methods addListener
, dispatchEvent
, and removeListener
, because they all work together and you don't want to mix native implementations with polyfills.
Removes all data model event handlers, detaching the data model from all grid instances.
This method is not called by Hypergrid but might be useful to applications for resetting a data model instance.
removeListener(handler)
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
If your data model does not implement this method, Local#resetDataModel
adds the default implementation from polyfills.js. If your data model does implement it, it should also implement the sister methods addListener
, dispatchEvent
, and removeAllListeners
, because they all work together and you don't want to mix native implementations with polyfills.
Detaches the data model from a particular grid instance.
This method is called by Hypergrid#desctruct
to clean up memory.
Note: destruct
is not called automatically by Hypergrid; applications must call it explicitly when disposing of a grid.
Parameters:
Name | Type | Description |
---|---|---|
handler |
DataModelListener | A reference to the handler originally provided to |
setData(data)
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Blah.
Parameters:
Parameters:
Name | Type | Description |
---|---|---|
data |
Array.<dataRowObject> | An array of congruent raw data objects. |
|
Array.<rawColumnSchema> | Ordered array of column schema. |
setMetadataStore(newMetadataStoreopt)
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Set the metadata store. The precise type of this object is implementation-dependent, so not defined here.
datasaur-base
supplies fallback implementations of this method as well as DataModel#getMetadataStore
which merely set and get this.metadata
in support of DataModel#setRowMetadata
and DataModel#getRowMetadata
.
Custom data models are not required to implement them if they don't need them.
If implemented, Hypergrid makes a single call to setMetadataStore
when data model is reset (see Local#resetDataModel
) with no arguments. Therefore this method needs to expect a no-arg overload and handle it appropriately.
Hypergrid never calls getMetadataStore
.
Parameters:
Parameters:
Name | Type | Attributes | Description |
---|---|---|---|
newMetadataStore |
<optional> |
New metadata store object. Omitted on data model reset. |
setRow(y, dataRowopt)
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Update or blank a row in place, without deleting the row (and without affecting succeeding rows' indexes).
Parameters:
Parameters:
Name | Type | Attributes | Description |
---|---|---|---|
y |
number | ||
dataRow |
object |
<optional> |
if omitted or otherwise falsy, row renders as blank |
setRowMetadata(y, newMetadataopt)
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Set the row's metadata object, which is a hash of cell properties objects, for those cells that have property overrides, keyed by column name; plus a row properties object with key __ROW
when there are row properties.
The default implementations of getRowMetadata
and setRowMetadata
store the metadata in an in-memory table. If this is not appropriate, override these methods to store the meta somewhere else (e.g., with the data in a hidden column, in another database table, in local storage, etc.).
Parameters:
Parameters:
Name | Type | Attributes | Description |
---|---|---|---|
y |
number | Row index. |
|
newMetadata |
object |
<optional> |
When omitted, delete the row's metadata. |
setSchema(newSchemaopt)
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Define column indexes. May include header
, type
, and calculator
properties for each column.
When the schema changes, the data model should dispatch the fin-hypergrid-schema-loaded
event, which tells Hypergrid to decorate
the schema and recreate the column objects.
It is not necessary to call on every data update when you expect to reuse the existing schema.
Parameters:
Parameters:
Name | Type | Attributes | Description |
---|---|---|---|
newSchema |
Array.<(columnSchema|string)> |
<optional> |
String elements are immediately converted (by |
setValue(columnIndex, rowIndex, newValue)
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Set a cell's value given its column & row indexes and a new value.
Parameters:
Parameters:
Name | Type | Description |
---|---|---|
columnIndex |
number | |
rowIndex |
number | |
newValue |
* |
toggleRow(rowIndex, columnIndexopt, toggleopt) → {boolean|undefined}
Mouse was clicked on a grid row.
IMPLEMENTATION OF THIS METHOD IS OPTIONAL.
Hypergrid calls this method from one place, behavior.cellClicked
, which is called from src/features/CellClick when user clicks on a tree or data cell.
The data model may consume or ignore the click.
If the data model consumes the click by modifying some data in the existing data set, it should dispatch the 'fin-hypergrid-data-loaded` data event to the grid, which causes a grid "repaint" (which re-renders rows and columns in place).
If the data model consumes the click by transforming the data, it should dispatch the following data events to the grid:
- 'fin-hypergrid-data-prereindex' before transforming the data
- 'fin-hypergrid-data-postreindex' after transforming the data
This causes Hypergrid to save the current row and/or column selections before and then attempt to restore them after, before a "shape change" (which recalculates row and column bounding rects and then re-renders them).
"Transforming the data" means altering the data set (by adding/removing rows, etc.). The typical use case for this is a click on a cell containing a drill-down control.
After rerendering, Hypergrid dispatches a DOM event with the same type (same event string) to the grid's <canvas>
element for the benefit of any application listeners.
Parameters:
Parameters:
Name | Type | Attributes | Description |
---|---|---|---|
rowIndex |
number | ||
columnIndex |
number |
<optional> |
For the drill-down control use case, implementations should call |
toggle |
boolean |
<optional> |
One of:
|
Returns:
If click was consumed by the data model:
undefined
Not consumed: Row had no drill-down control.true
Consumed: Row had a drill-down control which was toggled.false
Not consumed: Row had a drill-down control but it was already in requested state.NOTE: Implementation of a return value is optional as of version v3.0.0. It may be useful for testing purposes but
Hypergrid#cellClicked
no longer uses the return value (depending instead on the implementation dispatching data events), so implementations no longer need to support it. Therefore, in general, applications should no depend on a return value. For particular requirements, however, an applications may make a private contract with a data model implementation for a return value (that may or may not follow the above definition. Regardless of the implementation, the return value of this method is propagated through the return values ofLocal#cellClicked
->Hypergrid#cellClicked
-> the application.
- Type
- boolean | undefined
Events
fin-hypergrid-data-loaded
The data model should trigger this event when it changes the data on its own.
Hypergrid responds by calling grid.repaint()
— before triggering a grid event using the same event string, which applications can listen for using addEventListener
:
grid.addEventListener('fin-hypergrid-data-loaded', myHandlerFunction);
This event is not cancelable.
fin-hypergrid-data-postreindex
The data models should trigger this event immediately after data model remaps the rows.
Hypergrid responds by reselecting the remaining rows matching the indices previously saved in the data-prereindex
event, and then calling grid.behaviorShapeChanged()
— before triggering a grid event using the same event string, which applications can listen for using addEventListener
:
grid.addEventListener('fin-hypergrid-data-postreindex', myHandlerFunction);
This event is not cancelable.
fin-hypergrid-data-prereindex
The data models should trigger this event immediately before data model remaps the rows.
Hypergrid responds by saving the underlying row indices of currently selected rows — before triggering a grid event using the same event string, which applications can listen for using addEventListener
:
grid.addEventListener('fin-hypergrid-data-prereindex', myHandlerFunction);
This event is not cancelable.
fin-hypergrid-data-shape-changed
The data model should trigger this event when it changes the data rows (count, order, etc.) on its own.
Hypergrid responds by calling grid.behaviorChanged()
— before triggering a grid event using the same event string, which applications can listen for using addEventListener
:
`js
grid.addEventListener('fin-hypergrid-data-shape-changed', myHandlerFunction);
This event is not cancelable.
fin-hypergrid-schema-loaded
The data models should trigger this event on a schema change, typically from setSchema, or wherever schema is initialized. Hypergrid responds by normalizing and decorating the schema object and recreating the grid's column objects — before triggering a grid event using the same event string, which applications can listen for using addEventListener
:
grid.addEventListener('fin-hypergrid-schema-loaded', myHandlerFunction);
This event is not cancelable.