Dojo’s store API is a common interface for providing data to user interface widgets, such as dgrid, Dijit Select, and Dojo Charting. The beauty of having a consistent API is that once you’ve defined an interface for a data source, that data becomes easily available to all widgets that support the store API. We’re going to look at how you can create a basic, read-only dojo/store
API-compliant module for accessing GitHub’s API (specifically, GitHub issues), an example of implementing your own Dojo store.
Implementing basic store methods
For starters, we don’t have to implement all store methods – each method is optional. For a read-only store the most important methods are get
and query
. These methods enable basic read access to the data: get
to retrieve an item by its id, and query
to retrieve a set of items that match user-specified criteria. Let’s start with the basic framework and the get
method.
- GitHub’s API URL: https://api.github.com/
- The API URL for dgrid issues: https://api.github.com/repos/SitePen/dgrid/issues
- The identity property for a GitHub issue: each issue has an “id” property, but they also have a “number” property – the number is the value displayed in the GitHub UI, and the value that must be provided to the API when requesting a specific issue, so we will use the “number” property as the
idProperty
in our store - Dojo’s
dojo/request/script
module provides a convenient API for JSONP requests
With this information we can begin our implementation:
define([
'dojo/_base/declare',
'dojo/_base/lang',
'dojo/request/script',
'dojo/store/util/QueryResults'
], function (declare, lang, request, QueryResults) {
return declare(null, {
target: '',
idProperty: 'number',
constructor: function (options) {
lang.mixin(this, options);
},
get: function (id) {
return request(this.target + '/' + id, {
jsonp: 'callback'
}).then(function (result) {
// The information we want is on the 'data'
// property of the returned results
return result.data;
});
}
});
});
This short module is enough to begin making GitHub API requests using the Dojo store API:
var dgridIssueStore = new GitHubStore({
target: 'https://api.github.com/repos/SitePen/dgrid/issues'
});
// Get the JSON data for issue 840
dgridIssueStore.get(840);
What’s a store without a query
method?
The ability to query a store is very important, so we have more to do. A basic query method can be implemented very simply:
query: function (query, queryOptions) {
var resultPromise = request(this.target, {
query: query,
jsonp: 'callback'
}).then(function (result) {
// The information we want is on the 'data'
// property of the returned results
return result.data;
});
// QueryResults will add the 'total' property
// as well as iteration methods
return QueryResults(resultPromise);
}
Let’s examine how this works:
- Line 2: Make the JSONP request, adding any query options to the query string of the request URL (valid options for GitHub issues)
- Line 5: The data value returned should be an array of data, but the GitHub API provides an object with the array stored in the object’s
data
property, so we have to return a promise that resolves to the array in thedata
property (line 8). - Line 13: The
dojo/store
API requires that the object returned by thequery
method have iteration methods (forEach, filter, map
) and atotal
property. Thedojo/store/util/QueryResults
module is a utility module to add these.
Let’s implement the getIdentity
method to have a fairly robust read-only store:
getIdentity: function (object) {
return object[this.idProperty];
}
That’s it! This store is ready to query GitHub and provide data for a store-backed user interface widget. Here is the store in action with dgrid to render the data:
require({ baseUrl: 'http://ajax.googleapis.com/ajax/libs/dojo/1.9.3/', packages: [{ name: 'dojo', location: 'dojo' }, { name: 'dgrid', location: 'http://dojofoundation.org/packages/dgrid/js/dgrid' }, { name: 'put-selector', location: 'http://dojofoundation.org/packages/dgrid/js/put-selector' }, { name: 'xstyle', location: 'http://dojofoundation.org/packages/dgrid/js/xstyle' }] }, [ 'dojo/_base/declare', 'dojo/_base/lang', 'dojo/request/script', 'dojo/store/util/QueryResults', 'dgrid/OnDemandGrid' ], function (declare, lang, request, QueryResults, OnDemandGrid) { var GitHubStore = declare(null, { target: '', idProperty: 'number', constructor: function (options) { lang.mixin(this, options); }, get: function (id) { return request(this.target + '/' + id, { jsonp: 'callback' }).then(function (result) { // The information we want is on the 'data' property of the returned results return result.data; }); }, getIdentity: function (object) { return object[this.idProperty]; }, query: function (query, queryOptions) { var resultPromise = request(this.target, { query: query, jsonp: 'callback' }).then(function (result) { // The information we want is on the 'data' property of the returned results return result.data; }); // QueryResults will add the 'total' property as well as iteration methods return QueryResults(resultPromise); } }); var store = new GitHubStore({ target: 'https://api.github.com/repos/SitePen/dgrid/issues' }); var grid = new OnDemandGrid({ store: store, columns: { user: { label: 'Opened by', get: function (rowObject) { return rowObject.user.login; }, sortable: false }, title: { label: 'Title', sortable: false }, number: { label: 'Number', formatter: function (number) { return '<a href="https://github.com/SitePen/dgrid/issues/' + number + '">' + number + '</a>'; }, sortable: false } }, // Unauthenticated GitHub API requests are rate limited to 60/hr noDataMessage: 'GitHub API request rate exceeded - please try later' }, 'grid'); });
Production-ready stores
While the store API at its core is pretty simple, the data service API can complicate things, and in this case it does. GitHub’s API does not quite allow arbitrary page sizes, which is part of why we have omitted support for queryOptions
(which allows specification of sort, start, and count options) in the query
method. You might also want to implement authentication. Server-backed stores are generally dependent on the server for correct paging, sorting, and querying. For GitHub these query options are available. If the data set is small enough, you can load it all client-side and forego your own store implementation – just use dojo/store/Memory
.
Learning more
We cover dojo/store
, dgrid, dojo/request
, advanced store creation, and more in depth in our Dojo workshops offered throughout the US, Canada, and Europe, or at your location. We also provide expert JavaScript and Dojo support and development services, to help you get the most from JavaScript and Dojo.