Using Grids and Stores

In previous dgrid tutorials, you may have noticed demos which create grids
referencing
dstore instances. This tutorial will delve into the
topic of store communication in more detail, and demonstrate dgrid's
OnDemandList and Pagination components
which interact with stores in various ways.

dstore provides a common API for accessing and
manipulating data. It is intended to replace dojo/store and the
older dojo/data API. Starting with 0.4 dgrid interfaces
directly with dstore stores. Previous releases of dgrid worked with dojo/store
instances, and the older dojox/grid works with the older
dojo/data API.

If this is your first time working with dstore, we recommend starting by
familiarizing yourself with dstore
Collections and
Stores.

Before diving into specific components, it is important to understand a
few fundamental details of how dgrid interacts with stores. Many of
these principles are also applicable to other widgets.

Uniquely Identifying Store Items

Stores are used to represent collections of data items. It is quite
common for these items to possess a field which uniquely identifies each
item, making it possible to request a specific item. In the
dstore API, this ability is represented by the get and
getIdentity methods. Various dgrid components rely on these
methods in order to access the item represented by a specific row,
so stores used with dgrid need to support these methods.

In order for these methods to work, the store needs to know how to
uniquely identify items. This is typically achieved by specifying
idProperty in the arguments passed to the store constructor.
If not specified, it usually defaults to "id".

Querying Stores

When widgets interact with stores, they do so by directly calling the
store's methods. For example, dgrid components call stores' sort
and fetchRange methods, since sort and range behavior are
controlled through dgrid components or its user interface.

When dgrid interacts with a store, all paging, filtering, and sorting
responsibilities fall upon the store, not the grid. As a result, dgrid
has a tendency to bring store- or service-related issues to light.
When encountering data rendering issues, always check that the
store implementation (and backend service, if applicable) are performing
as expected. Don't forget to consult the store documentation; links for the
implementations shipped with dstore are included at the end of this tutorial.

With these general principles now behind us, let's take a look at the
components dgrid offers for presenting store data.

Virtual Scrolling with OnDemandGrid

When using dgrid with stores, the most commonly-used component is
OnDemandGrid, which combines the tabular display logic of
Grid with the on-demand loading and rendering of
OnDemandList. The result is a grid which scrolls fluidly as
if all items were rendered, but only actually requests items from the
store as necessary to fill the current viewport. Developers migrating to
dgrid from
dojox/grid/DataGrid should find this behavior familiar.

The following example creates a grid which will query an in-memory store.
The store is populated with data fetched using dstore's dstore/RequestMemory module.

Note that unlike previous versions of dgrid, dgrid 0.4 and later expose a
collection property instead of store.
In dstore, collections are a broader concept, and stores are also collections.

OnDemandList and OnDemandGrid provide a number
of properties for fine-tuning the lazy-loading behavior, though in many
cases, the default values will suffice. The following list outlines a
few of the most commonly-altered settings:

minRowsPerPage

The minimum number of items to request from the store at a given time.
This number should never be less than the number of rows expected to
be visible in the grid at any given time, in order to avoid excessive
queries. The default is 25.

farOffRemoval

The distance, in pixels, at which to consider rows far enough away
from the current viewport to begin removing them from the DOM. This can
be reduced to more aggressively remove rows from the DOM as the user
scrolls away, but it should never be less than the height of the grid.
The default is 2000.

pagingDelay

The minimum amount of time (in milliseconds) to wait after scrolling
occurs before requesting items from the store. This prevents excessive
querying as the user is scrolling, which is especially important when
using a store that retrieves data from a server on every call to
range or fetch. The default is 15.

The following demo includes two instances of OnDemandGrid
with different settings for minRowsPerPage and
farOffRemoval, to provide an example of how changing these
properties can affect user experience.

The Pagination Extension

While the virtual scrolling provided by OnDemandGrid is
often preferable, sometimes an application calls for presenting data in
discrete pages, following a more traditional approach. dgrid includes a
Pagination extension for this purpose, displaying a set number of
results at any given time. The Pagination extension
populates a footer area with controls to switch between pages, which can
be customized via various properties outlined in the
Pagination documentation.

Note that the Pagination extension is incompatible with
OnDemandGrid, since each has its own way of dealing with
collection ranges. Pagination should be mixed into
Grid, notOnDemandGrid.

The following example is very similar to the first
OnDemandGrid example above, but instantiates a
Grid with the Pagination extension mixed in
instead:

Handling Errors

You may have noticed that there is no equivalent for defining an error
message. This is because errors can occur for a wide variety of reasons,
at different points in time, so it is difficult to provide one place for
an error message that fits all situations. However, dgrid instances will
emit a dgrid-error event when an error occurs during a
store operation. This event can be listened to in order to react
however is deemed appropriate.

In addition to the dgrid-error event, the
OnDemandGrid and Pagination modules also
emit a dgrid-refresh-complete event any time a refresh
call completes successfully.

The following example demonstrates listening to these two events in
conjunction to show or hide a node containing an error message:

APIs for Customizing Queries

Earlier, we mentioned that dgrid issues dstore API calls for controlling
sort order and fetching data ranges. Filtering restrictions,
on the other hand, are not governed by dgrid components; instead, you
pass a filtered collection to the grid's collection property.
The collection and sort can be set when calling the constructor:

collection

Specifies the collection to fetch items from. This can be a store, or
an already-processed (e.g. filtered) collection.

sort

Specifies the sort order to be used for fetch requests. The value is
normally an array of objects where each object contains a
property named property identifying the data field to sort,
and optionally a descending property which, if true,
indicates to sort descending rather than ascending. For simple cases,
dgrid supports passing a string, simply referencing the name of a
data field to be sorted in ascending order.

These options can also be modified later after instantiation, using the
set method:

set("collection", newCollection)

Instructs the grid to reference a different collection.

set("sort", newSort)

Resets the sort order passed to fetch requests.

In order to filter the data in dgrid to a subset of the store's data
(i.e. perform a custom query), set the grid's collection to a
collection returned by a filter call to the store.

The following example demonstrates hooking up form controls to handlers
which use the set method to update sort and
provide a filtered collection:

Remember that dgrid only understands dstore APIs.
In cases where you need to connect to a dojo/store instance
with dgrid, wrap the store using the
dstore/legacy/StoreAdapter
module.

If you need to connect to a store using the older dojo/data
API, you will still need to use dstore's StoreAdapter, but
you'll first need to wrap the store using the
dojo/store/DataStore module.

Conclusion

dgrid offers two distinct ways to efficiently retrieve data using the
dstore API: the OnDemandList and
OnDemandGrid modules, and the Pagination mixin.
These components directly interact with a collection's fetchRange
and sort APIs, which are expected to handle all logic
pertaining to sorting and paging.