-
Notifications
You must be signed in to change notification settings - Fork 143
Row and cell properties as metadata
Metadata is defined as information about other data. In Hypergrid, metadata refer to properties that help display the actual grid data.
Row and cell properties collections are row-specific data that parallel the row data (as "row metadata" or simply "metadata"). Both these collections can include all the usual Hypergrid properties, such as color, alignment, cell dimensions, padding, what formatter and/or cell renderer to use, etc.
Metadata is stored either:
- with the data itself, persisted to the back end
- in a temporary parallel array, lost when the application is closed
Storing metadata with the data rows makes it especially convenient to persist the metadata along with the actual row data. Persisted metadata has advantages, such as for frequently changing rows and cells and/or when the application does not necessarily know what rows and cells need decorating.
Where the metadata is stored is handled by the data model when it implements getRowMetaData
and setRowMetaData
. Otherwise, the fallbacks for these methods store the metadata temporarily in a parallel array.
Prior to Hypergrid 3.0.0, metadata was implemented as a hard-coded hack, using getRow().__META
for the hash of column properties objects (keyed by column name) and getRow().__ROW
for row properties. This was a hack because among other things it assumed that the object returned by getRow()
was easily extensible. This worked fine for the local data model, but we can no longer assume this. The legacy implementation was also inflexible. It always stored metadata along with the actual data; and always stored it using __META
and __ROW
.
By relying instead on the data model to provide this logic, the data model now has the option to support persisted metadata however it likes by implementing the two new methods are described in this document. The details of the implementation are hidden from Hypergrid. If the data source does not implement the new interface, Hypergrid falls back to transient (non-persisted) storage of row and cell properties.
v3.0.0 introduces two new data model methods, setRowMetadata
and getRowMetadata
, which set and get a single metadata object. This change does several things:
- Defines a single metadata object. (Previously we had two separate metadata objects for row and cell properties.)
- Formalizes metadata access without the use of
getRow()
. - Hides the implementation details from Hypergrid by encapsulating metadata access inside the data source.
It is now up to the data source how to store the metadata. (Although the new local data source, datasaur-local
, actually uses the same dataRow.__META
property as before for what is essentially the same hash of column properties objects.)
The following examples show how we are no longer dependent on getRow()
or __META
.
These examples are for illustrative purposes only. In practice, developers access cell properties with setCellProperty
and getCellProperty
(and other sister) functions in Behavior.js and Column.js; and row properties with getRowProperties
, setRowProperty
, setRowProperties
, and addRowProperties
. (To access the height
row property specifically, developers can use setRowHeight
and getRowHeight
.)
Sets metadata object destructively, overwriting any existing metadata object:
dataSource.setRowMetadata(99, { null: 30, lastName: { color: 'red' } });
Omitting the second parameter deletes the metadata:
dataSource.setRowMetadata(99); // deletes row 99's metadata
The following example:
- Gets existing metadata object; else creates and returns it.
- Sets font color for a particular cell.
- Sets a row property:
var props = dataSource.getRowMetadata(99) || dataSource.setRowMetadata(99, {});
(props.lastName = props.lastName || {}).color = 'red';
(props.__ROW = props.__ROW || {}).backgroundColor = 'yellow';
The first line in the preceding example can be simplified by providing a second parameter to getRowMetadata
which creates and embeds a new object, based on the given prototype, guaranteeing an object is returned without an additional conditional call to setRowMetadata
:
var props = dataSource.getRowMetadata(99, null);
This is more performant because it saves doing the row lookup twice.
Note that null
creates a metadata object without a prototype, which is fine. To have it create the more familiar object based on Object
, give Object.prototype
instead of null
.
If these methods are unimplemented in the data source, Hypergrid's fallbacks for these methods warehouse the metadata in a parallel array (which would have to be saved and reloaded separately to persist the row and cell properties).
To conform to the "single metadata object" concept, the row properties object is now just another metadata property (though still named __ROW
). This means that while cell properties is a backwards-compatible data structure, row properties is not. The row properties object has been moved to inside the metadata object (dataRow.__META.__ROW
). The previous definition of row properties (dataRow.__ROW
) is now undefined.
This is a breaking change. Not terrible as the chances are there are few if any apps out there actually dependent on this data structure for row height. Although I realize we could have avoided the change by coding getRowMetadata
to return it inside a single metadata object even if it wasn't actually stored that way, this would have meant building a metadata object on every call and because it's called so frequently (in the low-level loop for cell rendering), this definitely would have impacted performance. Therefore I believe it is worth the change.