- The Book of Dojo
- Quick Installation
- Hello World
- Debugging Tutorial
- Introduction
- Part 1: Life With Dojo
- Part 2: Dijit
- Part 3: JavaScript With Dojo and Dijit
- Part 4: Testing, Tuning and Debugging
- Part 5: DojoX
- The Dojo Book, 0.4
dojo.data.ItemFileReadStore
Submitted by shaneosullivan on Fri, 07/13/2007 - 20:33.
Summary:
Dojo core provides a basic implementation of a read-only datastore, ItemFileReadStore
. This store reads the JSON structured contents from an http endpoint (service or URL), or from an in-memory JavaScript object, and stores all the items in-memory for simple and quick access. ItemFileReadStore
is designed to allow for flexibility in how it represents item hierarchy, references, and custom data types. It also provides options for which attribute can act as the unique identifier (for dojo.data.api.Identity
), and which attribute can be used as a general label for an item. This store has an expectation that data is provided to in in a specific though very flexible, format. All of the examples on this page demonstrate the general format expected.
The following dojo.data APIs are implemented by ItemFileReadStore
- dojo.data.api.Read
- dojo.data.api.Identity
Format Examples: The following examples of data conform to the format the store requires for item input.
JSON with References: The following geography example uses references (items referencing another item declared in the data):
{ 'identifier': 'name', 'label': 'name', 'items': [ { 'name':'Africa', 'type':'continent', 'children':[{'_reference':'Egypt'}, {'_reference':'Kenya'}, {'_reference':'Sudan'}] }, { 'name':'Egypt', 'type':'country' }, { 'name':'Kenya', 'type':'country', 'children':[{'_reference':'Nairobi'}, {'_reference':'Mombasa'}] }, { 'name':'Nairobi', 'type':'city' }, { 'name':'Mombasa', 'type':'city' }, { 'name':'Sudan', 'type':'country', 'children':{'_reference':'Khartoum'} }, { 'name':'Khartoum', type:'city' }, { 'name':'Asia', 'type':'continent', 'children':[{'_reference':'China'}, {'_reference':'India'}, {'_reference':'Russia'}, {'_reference':'Mongolia'}] }, { 'name':'China', 'type':'country' }, { 'name':'India', 'type':'country' }, { 'name':'Russia', 'type':'country' }, { 'name':'Mongolia', 'type':'country' }, { 'name':'Australia', 'type':'continent', 'population':'21 million', 'children':{'_reference':'Commonwealth of Australia'}}, { 'name':'Commonwealth of Australia', 'type':'country', 'population':'21 million'}, { 'name':'Europe', 'type':'continent', 'children':[{'_reference':'Germany'}, {'_reference':'France'}, {'_reference':'Spain'}, {'_reference':'Italy'}] }, { 'name':'Germany', 'type':'country' }, { 'name':'France', 'type':'country' }, { 'name':'Spain', 'type':'country' }, { 'name':'Italy', 'type':'country' }, { 'name':'North America', 'type':'continent', 'children':[{'_reference':'Mexico'}, {'_reference':'Canada'}, {'_reference':'United States of America'}] }, { 'name':'Mexico', 'type':'country', 'population':'108 million', 'area':'1,972,550 sq km', 'children':[{'_reference':'Mexico City'}, {'_reference':'Guadalajara'}] }, { 'name':'Mexico City', 'type':'city', 'population':'19 million', 'timezone':'-6 UTC'}, { 'name':'Guadalajara', 'type':'city', 'population':'4 million', 'timezone':'-6 UTC' }, { 'name':'Canada', 'type':'country', 'population':'33 million', 'area':'9,984,670 sq km', 'children':[{'_reference':'Ottawa'}, {'_reference':'Toronto'}] }, { 'name':'Ottawa', 'type':'city', 'population':'0.9 million', 'timezone':'-5 UTC'}, { 'name':'Toronto', 'type':'city', 'population':'2.5 million', 'timezone':'-5 UTC' }, { 'name':'United States of America', 'type':'country' }, { 'name':'South America', 'type':'continent', 'children':[{'_reference':'Brazil'}, {'_reference':'Argentina'}] }, { 'name':'Brazil', 'type':'country', 'population':'186 million' }, { 'name':'Argentina', 'type':'country', 'population':'40 million' } ]}
JSON with Hierarchy: The following geography example uses hierarchical items (items that contain definitions of other items):
{ 'identifier': 'name', 'items': [ { 'name':'Africa', 'type':'continent', children:[ { 'name':'Egypt', 'type':'country' }, { 'name':'Kenya', 'type':'country', children:[ { 'name':'Nairobi', 'type':'city' }, { 'name':'Mombasa', 'type':'city' } ] }, { 'name':'Sudan', 'type':'country', 'children': { 'name':'Khartoum', 'type':'city' } } ] }, { 'name':'Asia', 'type':'continent', 'children':[ { 'name':'China', 'type':'country' }, { 'name':'India', 'type':'country' }, { 'name':'Russia', 'type':'country' }, { 'name':'Mongolia', 'type':'country' } ] }, { 'name':'Australia', 'type':'continent', 'population':'21 million', 'children': { 'name':'Commonwealth of Australia', 'type':'country', 'population':'21 million'} }, { 'name':'Europe', 'type':'continent', 'children':[ { 'name':'Germany', 'type':'country' }, { 'name':'France', 'type':'country' }, { 'name':'Spain', 'type':'country' }, { 'name':'Italy', 'type':'country' } ] }, { 'name':'North America', 'type':'continent', 'children':[ { 'name':'Mexico', 'type':'country', 'population':'108 million', 'area':'1,972,550 sq km', 'children':[ { 'name':'Mexico City', 'type':'city', 'population':'19 million', 'timezone':'-6 UTC'}, { 'name':'Guadalajara', 'type':'city', 'population':'4 million', 'timezone':'-6 UTC' } ] }, { 'name':'Canada', 'type':'country', 'population':'33 million', 'area':'9,984,670 sq km', 'children':[ { 'name':'Ottawa', 'type':'city', 'population':'0.9 million', 'timezone':'-5 UTC'}, { 'name':'Toronto', 'type':'city', 'population':'2.5 million', 'timezone':'-5 UTC' }] }, { 'name':'United States of America', 'type':'country' } ] }, { 'name':'South America', 'type':'continent', children:[ { 'name':'Brazil', 'type':'country', 'population':'186 million' }, { 'name':'Argentina', 'type':'country', 'population':'40 million' } ] } ] }
Custom Data Types: The following example uses custom data types (items with custom data types):
{ 'identifier': 'abbr', 'label': 'name', 'items': [ { 'abbr':'ec', 'name':'Ecuador', 'capital':'Quito' }, { 'abbr':'eg', 'name':'Egypt', 'capital':'Cairo' }, { 'abbr':'sv', 'name':'El Salvador', 'capital':'San Salvador' }, { 'abbr':'gq', 'name':'Equatorial Guinea', 'capital':'Malabo' }, { 'abbr':'er', 'name':'Eritrea', 'capital':'Asmara', 'independence':{'_type':'Date', '_value':"1993-05-24T00:00:00Z"} // May 24, 1993 in ISO-8601 standard }, { 'abbr':'ee', 'name':'Estonia', 'capital':'Tallinn', 'independence':{'_type':'Date', '_value':"1991-08-20T00:00:00Z"} // August 20, 1991 in ISO-8601 standard }, { 'abbr':'et', 'name':'Ethiopia', 'capital':'Addis Ababa' } ]}
Note: For custom data types, ItemFileStore
looks for attributes that have an object format value and contains the following two specific attributes:
_type
- Attribute used to look up in the
typeMap
which constructor should be used to instantiate the custom data type. _value
- Parameter that is the data to be passed to the constructor of the type. In this case, the custom type is a JavaScript Date object, and its value is the ISO-8601 string format of the date.
- identifier
- Optional Metadata. The attribute in each item to act as the unique identifier for that item. This parameter is optional.
- label
- Optional Metadata. The attribute in each item to act as the human-readable label for that item. This parameter is optional.
- items
- An array of JavaScript objects that act as the items of the store. The attributes that are part of the items can be any valid JavaScript attribute name. Note that there is a special way for items to reference other items in the store when dealing with hierarchical data.
- url
- The URL from which to load the JSON data. This is optional. If it isn't specified, then you should specify the 'data' parameter to identify the in-memory javascript object that constitutes the basis for the store content.
- data
- The JavaScript object that represents the stores contents, as defined by the structure displayed in the examples. This is optional.
- typeMap
- A JavaScript associative map of data types to deserialize them. This is optional. See the Custom Data Type Mapping for more details.
NOTE: The top level wrapper of the input for each of these examples is a JavaScript object. It has the following basic attributes that define the list of items that constitute the data and meta information about them:
Constructor parameters
The constructor for ItemFileReadStore
takes the following possible parameters in its keyword arguments:
Custom Data Type Mappings
Custom data types are a way to specify how the store should interpret a value of an attribute on an 'item' when it is parsing and loading the store from the ItemFile format. The ItemFileReadStore has one built in custom data type; the 'Date' object. It, by default, maps attribute values of {_type: "Date" _value: "some ISO string"} to a new Date instance instead of treating that JS object as a child item with attributes of '_type' and '_value'. The ItemFileReadStore also allows users to define their own custom types so that they can control how the information in the ItemFile format is interpreted. There are a couple of ways to map custom data types. There is a simple mapping method and general purpose mapping method that are described in the following sections.
Simple mapping: Direct Constructor
The direct constructor approach is the simplest way to map a type. This example assumes that the value stored in _value
can be used as the parameter to the constructor for an object:
var typeMap = { "Color": dojo.Color, ... };
General Purpose Mapping
General purpose mapping is intended for cases where you cannot directly pass the value of _value
into a constructor. A good example of this is how Date
is mapped internally in ItemFileReadStore
. This is used because ItemFileReadStore
reads in the _value
for a date as a serialized ISO string, which is not a format the general JavaScript Date object understands.
The following example shows the Date serialization load from an ISOString format:
var typeMap = { "Date": { type: Date, deserialize: function(value){ return dojo.date.stamp.fromISOString(value); } } };
Query Syntax
The fetch method query syntax for ItemFileReadStore
is simple and straightforward. It allows a list of attributes to match against in an AND fashion. For example, a query object that looks like the following example will locate all items that have attributes of those names that match both of those values:
{ foo:"bar", bit:"bite"}
Note that ItemFileReadStore
supports the use of wild cards (multi-character * and single character ?) in its attribute value matching.
Examples
To find all items with attribute foo that start with bar, the query would be:
{ foo:"bar*"}
To find all items with attribute foo the value of which ends with ar and ignoring only the first character, the query would be:
{ foo:"?ar"}
NOTE: Other stores should follow the same semantics in defining queries for consistency.
Usage Examples
For these examples, we'll assume a data source as defined by the example data format in this page unless otherwise specified.
Example 1: Query for all continents
var store = new dojo.data.ItemFileReadStore({url: "geography.json"}); var gotContinents = function(items, request){ for (var i = 0; i < items.length; i++){ var item = items[i]; console.log("Located continent: " + store.getLabel(item)); } } var request = store.fetch({query: {type:"continent"}, onComplete: gotContinents});
Example 2: Query for names that start with A, case insensitively
var store = new dojo.data.ItemFileReadStore({url: "geography.json"}); var gotNames= function(items, request){ for (var i = 0; i < items.length; i++){ var item = items[i]; console.log("Located name that started with A: " + store.getLabel(item)); } } var request = store.fetch({query: {name:"A*"}, queryOptions: {ignoreCase: true}, onComplete: gotNames});
Example 3: Programmatic creation of ItemFileReadStore without a URL. Then query for names that start with J, case insensitively.
IMPORTANT NOTE: In this example the object 'dataItems' is modified and used directly by the store to generate the internal store representation of all the data. This is for efficiency of use and code size. If you want to repeatedly reuse the dataItems object you will need to clone the object and pass the clone into the store. If you do not clone the object and try to reuse dataItems, you will likely encounter errors due to the modifications the ItemFileReadStore applies to the data set so that it can perform store operations efficiently.var dataItems = { identifier: 'name', label: 'name', items: [ {name: 'John Smith'}, {name: 'Bob Smith'}, {name: 'Nancy Smith}', {name: 'John Doe'} ] }; var store = new dojo.data.ItemFileReadStore({data: dataItems}); var gotNames= function(items, request){ for (var i = 0; i < items.length; i++){ var item = items[i]; console.log("Located name that started with J: " + store.getLabel(item)); } } var request = store.fetch({query: {name:"J*"}, queryOptions: {ignoreCase: true}, onComplete: gotNames});
Further Examples
For further examples refer to the Using Datastores section of the Dojo book or refer to the test cases for dojo.data provided in the tests
sub-directory of your dojo distribution.
- Printer-friendly version
- Login or register to post comments
- Subscribe post
fetch context and scope attribute
If you use the fetch method within a self designed widget, you have to set the scope attribute to this {scope : this} to be able to refer to the widget self from within the callback functions. Otherwise, the context is set by default to data.global.
Best regards,
Roger
How to handle errors encountered in the constructor?
OK, I have an ItemFileReadStore that loads data from a url on the server. Then I have a dijit.Tree that subscribes to the data store.
Suppose the server is down.
Now, the ItemFileReadStore just catches the exception and logs it on the console. I see the bad HTTP responses also appear in the console. My Tree, however, remains empty, with no information sent to the user that the server is down.
How do I handle this error in a more intelligent way? So far, the only thing I've thought up involves setting up a poller that looks at the _loadFinished and _loadInProgress fields of the store, and yells if both are false; this is so obviously ugly that I don't want to do it. What's the design intention?
dijit.Tree problem.
That is a problem with dijit.Tree, not with dojo.data.ItemFileReadStore. They are not providing a way to expose the errors reported by the onError() handler functions (they may not even be using the onError handler functions). When an error occurs, the datastore will, if provided an onError() function, call that function with the error that occurred (including things like an HTTP timeout). What the user then does with that error object is up to the user. In this case, dijit.Tree, isn't reporting it very well or exposing it so that a Tree User can access it.
Get/Post + additional parameters
The current implementation of '_fetchItems' uses xhrGet, and the getArgs variable is created within the function.
This limits the usability, as there may be situations in which the url needs additional dynamic parameters, or where 'post' is preferred to 'get'.
Are there any plans to add this functionality ? Or other workarounds (except subclassing ItemFile(Read|Write)Store ?
thanks
nested objects in a grid
in the above example how do we use the nested data in a grid
How do you access
I'm posting this here, since I have a question, but I think the doc needs to be updated to explain this....
If I define the data items in Javascript....
identifier: 'name',
label: 'name',
items: [
{name: 'John Smith'},
{name: 'Bob Smith'},
{name: 'Nancy Smith}',
{name: 'John Doe'}
]
};
...how can I later refer to this javascript object in HTML? The following doesn't seem to work...
two ways to create a ItemFileReadStore
* using parser
<div dojoType="dojox.grid.data.DojoData" jsId="model" rowsPerPage="20" store="jsonStore" query="{ name: '*' }" clientSort="true"></div>
<div id="projectGrid" dojoType="dojox.Grid" model="model" structure="projectListLayout"></div>
* from json object in memory
"timestamp":1193692111,
items:[
{ id:1,name:"Project ayo", type:"Internal", pm:"D Z", created:"2/14/2008", modified:"2/14/2008", status:"Initialized", pp:null }
],
"identifier":"name",
"label":"name"
};
var jsonStore = new dojo.data.ItemFileReadStore({data:testStore});
<div id="projectGrid" dojoType="dojox.Grid" model="model" structure="projectListLayout"></div>
-----------------------------------------------
My dojo based applications
http://copropriete.clubimmo.com