
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
idPropertyin our store - Dojo’s
dojo/request/scriptmodule 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
dataproperty, so we have to return a promise that resolves to the array in thedataproperty (line 8). - Line 13: The
dojo/storeAPI requires that the object returned by thequerymethod have iteration methods (forEach, filter, map) and atotalproperty. Thedojo/store/util/QueryResultsmodule 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.
