Skip to content

Grid Properties

Jonathan Eiten edited this page Feb 23, 2018 · 15 revisions

Definition

When we speak collectively of grid properties (a.k.a. look & feel or LnF properties), we are actually referring to a stack of JavaScript objects that describe the appearance and behavior of the grid as well as individual columns, rows and cells.

This stack of properties collections (as we call them) takes full advantage of JavaScript's prototype chain.

Advisory: Before continuing, make sure you have a firm grasp of prototypal inheritance, specifically as pertains to plain objects: How the prototype chain works at a basic level, without regard to object constructors and methods, and what it means for an object to have been "extended from" or "created from" another object.

The semantics of the properties stack are laid out in the next section, but before we get to that let's define the various types of LnF properties collections.

Grid LnF props

Given a grid instance that models (represents) the grid,, for example var grid = new Hypergrid, the grid's properties collection is referenced as grid.properties.

Column LnF props

Columns are also backed by column objects. For example var column = grid.getColumn(i) models a given column i whose properties collection is referenced as column.properties. All column properties collections have their prototype set to grid.properties. In this way, a column LnF property overrides the grid LnF property of the same name — but only when the column has such a property; otherwise the grid property applies to that column.

Cell LnF props

For performance reasons, individual cells in Hypergrid are not modeled. They can however have a properties collection. Hypergrid only creates a cell properties collection when needed; cells with no LnF properties to override do not have a properties collection because they do not require one. Many methods exist for setting and getting cell LnF properties and cell properties collections, for example column.setCellProperty(y, key, value), which sets a property key on the cell in row y to value. Setting even a single LnF property on a cell creates a properties collection for that cell (with column.prototype as its prototype, and so forth, recalling that the column's prototype is in turn set to grid.properties). When an application tries to get a cell's LnF property but the cell doesn't actually have a properties collection, the column's LnF property with the same name is referenced instead. (There are also methods to explicitly reference a cell LnF property or property collection, returning results iff the collection exists.)

Row LnF props

Rows, like cells, are not modeled and only have LnF properties collections created for them as needed.

Implementation note: Unlike cell (and column) properties collections, row properties collections do not participate in the prototype chain. Row LnF properties must be explicitly copied to the LnF config object handed to the cell renderer for each and every cell. Furthermore, when cell LnF props are applied after row LnF props, the cells' props must be copied as well. None of this is necessary when row properties are disabled.

Row striping LnF props

Row stripes can be thought of as global row LnF properties, on top of which regular row LNF properties can be layered. Row properties objects exist in an array in the rowStripes property, which is provided modulo (cyclically). When rowStripes is falsy, there are no row stripes properties collections, and hence no row striping.

The properties stack

Each cell in a grid has a stack of properties collections objects, implemented as a JavaScript prototype chain.

This properties stack effects a cascade, somewhat like a web page's Cascading Style Sheets (CSS), which is to say that each cell of the grid is rendered according to a reduction of each of the layers described above. Properties defined in upper layers of the stack supersede those of the same name defined in lower layers. The bottom layer contains a complete set of defaults, fallback values for the required properties.

For each grid cell, the stack consists of the following layers, listed here from the bottom up:

Layer 1: Hypegrid.defaults

At the root of the properties stack is the defaults object, containing the default definitions for all properties. All succeeding layer are instance layers (owned by a specific grid instance).

This layer is common to all grid instances. Applying a global theme actually overwrites properties in this layer.

Synonym: Hypergrid.properties.

Layer 2. grid.theme

Each grid instance starts with it's own theme layer, which is where skin adjustments are applied.

Layer 3. grid.properties

Each grid instance continues with this properties layer, which contains the grid's "own" properties, including its dynamic grid property setters/getters.

Layer 4. column.properties

Each column object has its own properties object, extended from grid.properties.

Layer 5. cell.properties

Each cell may potentially have its own properties object, extended from the cell's column.properties object. Cell properties objects differ from the other properties objects, however, in that they are only created as needed. See Accessing cell properties below for more info.

Layer 6. config

This layer is only available at render time. This is the configuration object passed through the application's optional getCell function, which may freely mutate it, before it is then passed to the cell renderer.

Example

The properties stack effects a cascade, somewhat like a web page's Cascading Style Sheets (CSS), which is to say that each cell of the grid is rendered according to a reduction of each of the layers described above.

For example, consider a specific property, color. This property accepts a CSS color spec for rendering text. To set the text color for the entire grid (i.e., all cells of all columns) to red, simply set it on the grid properties object:

grid.properties.color = 'red';

To set only one column to red, set it on the column properties object:

var column = grid.behavior.getColumn(3);
column.properties.color = 'red';

To set all but one column to red:

grid.properties.color = 'red';
var column = grid.behavior.getColumn(3);
column.properties.color = grid.theme.color;

To set a particular cell to red, set it on the cell properties object:

grid.behavior.setCellProperty(99, 3, 'color', 'red');

which sets the color of only the cell on the 100th row in column 3 to red. Be careful when using the row index, which is subject to change if rows are added or deleted above it!

Dynamic Grid Properties

It is also possible to control grid properties programmatically. See Dynamic Grid Properties for more information.

Accessing cell properties

Accessing cell properties is not as straight-forward as accessing column and grid properties because cell properties objects are only created as needed. This is because Hypergrid does not model individual cells; there are no cell objects so you cannot simply say cell.properties.

Rather, individual cell properties are accessed via the various getCellProperty() and setCellProperty() methods, which is the recommended approach. (See above example.)

That said, if you prefer to work with a cell properties object directly, you can call getCellProperties(). However, if the cell does not have a properties object, this method will return its column's properties object instead, which is fine if you only intend to reference properties read-only. But if you wish to add a new property to a cell properties object, you must call addCellProperties() instead. If the cell had no properties object before, it will create an empty one and Object.assign new new properties to it. Both of the following do the same thing:

var column = grid.behavior.getColumn(3);
column.setCellProperty(99, 'color', 'red');

var cellProps = grid.behavior.addCellProperties(99, 3, { color: 'red' });

Only call this method when you intend to create a new cell property because otherwise you will end up littering your grid with empty cell properties objects which will eventually fill memory and are also non-performant.

Finally, to attach an entire properties object to a cell, you can call setCellProperties():

grid.behavior.setCellProperties(99, 3, { color: 'red' });

CellEvent objects

CellEvent objects are used extensively internally. These objects are created when cells are laid out for rendering. They contain many internal properties (mostly getters, actually) as well as access to the cell's properties object similar to the above. See the Working with CellEvent objects wiki for more information.