Skip to content

Core Components

csnover edited this page Dec 5, 2012 · 12 revisions

Core Components

dgrid's primary components fall into the following top-level modules.

List

This provides the basic facilities for taking an array of objects and rendering as rows of HTML in a scrollable area. This will automatically include touch scrolling capabilities (via the TouchScroll module) on mobile devices.

The List can be used to render an array of data. For example:

require(["dgrid/List"], function(List){
    // attach to a DOM element indicated by its ID
    var list = new List({}, "list");
    // render some data
    list.renderArray(arrayOfData);
});

APIs

The base List class (inherited by all other classes) exposes the following methods:

  • get(property): Returns the value of a given property. Supports custom getter implementations via the pattern _getProperty (which would map to get("property")).
  • set(property, value): Sets the value of a given property. Supports custom setter implementations via the pattern _setProperty (which would map to set("property", ...)).
  • row(target): This will look up the requested row and return a Row object. The single parameter may be a DOM event, DOM node, or in the case of store-backed components, a data object or its ID. The returned Row object has the following properties:
    • id: the data object's id
    • data: the data object represented by the row
    • element: the row's DOM element
  • up(row[, steps]): Given a row object (or something that resolves to one via the row method), returns a row object representing the row located steps rows above (where steps defaults to 1)
  • down(row[, steps]): Same as up(), but operating downward
  • on(event, listener): Basic event listener functionality; simply delegates to the top-level DOM element of the List, using standard dojo/on behavior.
  • renderArray(array, beforeNode, options): This can be called to render an array directly into the list. The beforeNode parameter can be used to render at a specific point in the list. Note that when using store-backed components, this is called automatically.
  • renderRow(item, options): This method can be overridden to provide custom rendering logic for rows. (The Grid module, introduced next, actually overrides this method.) item refers to the record from the grid’s data store for the row.
  • removeRow(rowElement, justCleanup): This method can be extended/aspected to perform cleanup logic when an individual row is removed.
  • set("sort", property, descending): This can be called to sort the List by a given property; if the second parameter is passed true, the sort will be in descending order. Multiple sort criteria can be specified in the format expected by stores' queryOptions (an array of objects with attribute and descending properties); this is also the format get("sort") will return in. The Grid and OnDemandList modules further extend sort functionality.
  • showHeader: Whether to display the header area; normally false for lists and true for grids. Can be reset later via set("showHeader", ...).
  • showFooter: Whether to display the footer area; false by default, but enabled and used by some extensions (e.g. Pagination). Can be reset later via set("showFooter", ...).
  • scrollTo(options): scrolls to a given point in the grid. Accepts x and y properties; if one is not given, position along that axis is not modified.
  • getScrollPosition(): returns the current position that the grid is scrolled to, in the form of an object containing x and y properties.

Lists, as well as all other dgrid components, maintain the following DOM references:

  • domNode: The top-level DOM node of the component (much like the domNode property of Dijit widgets).
  • headerNode: The DOM node representing the header region; mainly applicable to grid components.
  • bodyNode: The DOM node representing the body region (the area which will show rows for each item).
  • contentNode: The DOM node immediately under the bodyNode, which may potentially be scrolled to accommodate more content than the component's height will allow to fit.
  • footerNode: A DOM node appearing below the bodyNode; initially empty and not displayed by default.

Grid

Grid extends List to provide tabular display of data items, with different fields arranged into columns.

APIs

In addition to the List methods outlined above, Grid also exposes the following:

  • cell(target[, columnId]): Analogous to the row method, but at the cell level instead. The cell method can look up based on an event or DOM element, or alternatively, a data item (or ID thereof) and the ID of a column. Returns an object containing the following properties:
    • row: a Row object (as would be obtained from the row method) for the row the cell is within
    • column: the column definition object for the column the cell is within
    • element: the cell's DOM element
  • left(cell[, steps]): Given a cell object (or something that resolves to one via the cell method), returns a cell object representing the cell located steps cells to the left (where steps defaults to 1), wrapping to previous rows if necessary
  • right(cell[, steps]): Same as left(), but operating towards the right, wrapping to subsequent rows if necessary
  • column(target): Returns the column definition object for the given column ID; typically analogous to cell(...).column
  • styleColumn(columnId, css): Programmatically adds styles to a column, by injecting a rule into a stylesheet in the document. Returns a handle with a remove function, which can be called to later remove the added style rule.

Specifying grid columns

In the simplest cases, the columns of the grid are defined via the columns property. This property can be a hash (object) or array, containing column definition objects. When columns is an object, each property's key represents the id and field of the column, and each value is the column definition object. When columns is an array, the numeric indices become the column IDs; fields must be specified within each definition.

Generally, using object notation is slightly more concise and convenient. However, it's worth noting that doing so relies on the order of enumeration employed by the JavaScript runtime. Typically this isn't a problem, as it matches the order in which properties are specified, but one common exception is in the case of keys coercible to numbers.

For example, we could create a grid like so:

require(["dgrid/Grid"], function(Grid){
    var columns = {
        first: {
            label: "First Name"
        },
        last: {
            label: "Last Name"
        },
        age: {
            label: "Age",
            get: function(object){
                return (new Date() - object.birthDate) / 31536000000;
            }
        }
    };
    var grid = new Grid({ columns: columns }, "grid"); // attach to a DOM id
    grid.renderArray(arrayOfData); // render some data
    ...
});

Alternatively, the same columns as above could be defined in an array, as follows:

    var columns = [
        {
            label: "First Name",
            field: "first"
        },
        {
            label: "Last Name",
            field: "last"
        },
        {
            label: "Age",
            field: "age",
            get: function(object){
                return (new Date() - object.birthDate) / 31536000000;
            }
        }
    ];

A column definition may also be specified simply as a string, in which case the value of the string is interpreted as the label of the column. Thus, the simplest column structures can be more succinctly written:

var grid = new Grid({
    columns: {
        first: "First Name",
        last: "Last Name",
        ...
    },
    ...
}, ...);

Column Definition Properties

Each individual column definition object may have the following properties (all are optional):

  • field: The property from the object in the list to display in the body of the grid (unless otherwise overridden via the get function, explained below). In cases where columns is passed an object, the key of each property represents the field name, and thus this property is normally ommitted.
  • label: The label to show in the header of the grid. Defaults to the value of field.
  • className: A CSS class to assign to the cells in the column. If unspecified, a default class name of the form field-<field> is used, where <field> is the value of the field property.
  • id: The id of the column; normally this is determined automatically from the keys or indices in the columns object or array.
  • sortable: Indicates whether or not the grid should allow sorting by values in this field, by clicking on the column's header cell. Defaults to true.
    • Note that it is always possible to programmatically sort a Grid by a given field by calling set("sort", property, descending) regardless of sortable status or even visible presence in the Grid altogether.
  • get(item): An optional function that, given a data item, will return the value to render in the cell.
  • set(item): An optional function that, given a data item, will return the value to set for that column on that item. If no value is returned, the originally set value will be used.
  • formatter(value): An optional function that, given the value to be displayed, will return a string of HTML for rendering.
  • renderCell(object, value, node, options): An optional function that will be called to render the value into the target cell. object refers to the record from the grid’s store for the row, and value refers to the specific value for the current cell (which may have been modified by the column definition’s get function). node refers to the table cell that will be placed in the grid if nothing is returned by renderCell; if renderCell returns a node, that returned node will be placed in the grid instead. (Note: if formatter is specified, renderCell is ignored.)
  • renderHeaderCell(node): An optional function that will be called to render the column's header cell. Like renderCell, this may either operate on the node directly, or return a node to be placed within it.

Subrows

The Grid component also supports structures with multiple "subrows"; that is, it supports the idea of rendering multiple rows for each data item. Specification of multiple subrows is very much like specifying columns, except that one uses the subRows property instead of columns, and it receives an array of columns objects/arrays.

Both the columns and subRows properties can be later reset by using the central set method.

By default, the Grid renders a header, containing cells which display the label of each column. This can be disabled by setting showHeader: false in the arguments object to the Grid; it can also be changed later using set("showHeader", ...).

Specifying Columns via HTML: GridFromHtml

Some developers prefer specifying column layouts in an actual table structure because it is more convenient or semantically clearer. dgrid supports this via the GridFromHtml module. When using this module, a table element should be specified as the source node for the grid instance; it then scans for th nodes within rows (typically placed inside the thead) to determine columns.

Column properties are specified within the th, primarily via the data-dgrid-column attribute, which should contain a JavaScript object. Properties which coincide with standard HTML attributes can also be specified as such, e.g. class, rowspan, and colspan. The innerHTML of the th is interpreted as the column's label by default.

Note that unlike data-dojo-props, data-dgrid-column requires that you include the surrounding curly braces around the object - this allows alternatively specifying a column plugin instead of just a straight-up object. (Note, however, that referencing column plugins requires that they be exposed in the global scope, perhaps under a namespace.)

Examples of creating grids from HTML can be found in the GridFromHtml.html and complex_columns.html test pages.

It is also possible to specify columnsets (for the ColumnSet mixin) via HTML tables by using the GridWithColumnSetsFromHtml module. ColumnSets are expressed in HTML via colgroup tags. See the complex_columns.html test page for an example of this as well.

Dojo 1.7 Note: Using GridFromHtml with the Dojo Parser

The following note applies to Dojo 1.7 only; in Dojo 1.8 this becomes easier thanks to data-dojo-type supporting module IDs (see Dojo ticket #13778). Additionally, data-dojo-mixins can be used to declaratively compose dgrid instances including mixins.

Using the parser in Dojo 1.7 with modules designed purely in the AMD format can be a bit unwieldy, since the parser still expects data-dojo-type values to reference variables accessible from the global context. While existing Dojo 1.x components currently continue to expose globals, dgrid does not do so by default, since it is written purely in AMD format. Thus, when intending to parse over dgrid components, it is necessary to expose the components via a global namespace first. For example:

require(["dgrid/GridFromHtml", "dojo/parser", ..., "dojo/domReady!"],
function(GridFromHtml, parser, ...) {
    window.dgrid = { GridFromHtml: GridFromHtml };
    parser.parse();
});

This can be seen in practice in some of the test pages, such as GridFromHtml.html and dijit_layout.html.

OnDemandList

OnDemandList extends List to provide on-demand lazy loading of data as the user scrolls through the list. This provides a seamless, intuitive interface for viewing large sets of data in scalable manner.

OnDemandList inherits the _StoreMixin module, which implements a basis for interacting with a Dojo object store for querying of data. At minimum, this implementation expects a store supporting the get, getIdentity, and query methods.

OnDemandList requires that a store be specified via the store property, and will call the query method on the store to retrieve the data to be rendered. OnDemandList will call query with start and count options so as to only retrieve the necessary objects needed to render the visible rows. As the list or grid is scrolled, more query calls will be made to retrieve additional rows, and previous rows will be pruned from the DOM as they are scrolled well out of view.

When working with a writable store, for best results, the store should return query results with an observe method, which enables the list to keep its display up to date with any changes that occur in the store after the items are rendered. The dojo/store/Observable module can prove useful for adding this functionality.

_StoreMixin APIs

OnDemandList inherits the following properties and methods from _StoreMixin:

  • noDataMessage: An optional message to be displayed when no results are returned by a query.
  • loadingMessage: An optional message to be displayed in the loading node which appears when a new page of results is requested.
  • getBeforePut: if true (the default), any save operations will re-fetch the item from the store via a get call, before applying changes represented by dirty data.
  • query: An object to be passed when issuing store queries, which may contain filter criteria.
  • queryOptions: An object to be passed along with query when issuing store queries. Note that the standard start, count, and sort properties are already managed by OnDemandList itself.
  • store: An instance of a dojo/store implementation, from which to fetch data.
  • set("query", query[, queryOptions]): Specifies a new query object (and optionally, also queryOptions) to be used by the list when issuing queries to the store.
  • set("store", store[, query[, queryOptions]]): Specifies a new store (and optionally, also query and queryOptions) for the list to reference.
  • refresh(): Clears the component and re-requests the initial page of data.
  • set("sort", property, descending): _StoreMixin's version of this defers sorting to the store.
  • updateDirty(id, field, value): Updates an entry in the component's dirty data hash, to be persisted to the store on the next call to save().
  • save(): Instructs the list to relay any dirty data back to the store. Returns a promise which resolves when all necessary put operations have completed successfully (even if the store operates synchronously).
  • revert(): Clears the dirty data hash without updating the store, and refreshes the component.

OnDemandList APIs

OnDemandList also implements the following properties and methods, in addition to those inherited from _StoreMixin:

  • minRowsPerPage: The minimum number of items that will be requested at one time while scrolling; default is 25.
  • maxRowsPerPage: The maximum number of items that will be requested at one time while scrolling; default is 250.
  • maxEmptySpace: The maximum size (in pixels) of unrendered space below or above the rendered portion of the component; default is Infinity, which indicates that the size of unrendered space should approximate the total space which would be occupied by all items in the result set.
  • bufferRows: The number of rows to keep rendered beyond each end of the currently visible area of the component; default is 10.
  • farOffRemoval: The minimum distance (in pixels) which must exist between the currently visible area and previously-rendered rows before they are removed from the DOM; default is 2000, but this can be adjusted based on a known maximum height in cases where keeping fewer nodes in the DOM is preferable.
  • queryRowsOverlap: Specifies the number of items to "overlap" between queries, which helps ensure consistency of observed updates to items at page boundaries. The default is 1.
  • pagingDelay: Specifies the minimum number of milliseconds between processing of scroll position changes (and thus also potential store requests when scrolling rapidly); default is 15.
  • renderQuery(query): Renders the given query into the list. Called automatically upon refresh.

Events

If something should go wrong within OnDemandList's logic, _StoreMixin is equipped to emit a dgrid-error event, including the following properties:

  • grid: The Grid (or List) instance on which the error occurred
  • error: The error which occurred

OnDemandList emits a dgrid-error event for any error that occurs while querying the store for data in reaction to scrolling or a refresh call.

OnDemandGrid

This module is simply the composition of Grid and OnDemandList. For example:

define(["dgrid/OnDemandGrid"], function(Grid){
    grid = new Grid({
            store: myStore, // a Dojo object store
            columns: [
                {label: "Column 1", field: "col1", sortable: false},
                {label: "Column 2", field: "col2"},
                ...
            ]
        }, "grid");
    ...
});
Clone this wiki locally