RESTful JSON + Dojo Data

By on June 13, 2008 12:03 am

jsonreststore-simple.png

NOTE: This post is very out of date. For more up to date information about RESTful JSON in Dojo applications there are a number of more recent tutorials are available, such as the Dojo Store introduction, as well as tutorials demonstrating store-driven grids and trees, among others. You should also take a look at dstore, the next generation Dojo store architecture, for an even more modern take on RESTful JSON. We have a series of tutorials introducing the concepts.

Dojo 1.2 now includes an infrastructure for interacting with JSON REST services and data storage systems. JsonRestStore is a new Dojo Data store for interacting with the RESTful JSON data sources. This new data store allows you to communicate with server side database/persistent data storage using the Dojo Data API with JavaScript and efficiently handles create, read, update, and delete (CRUD) operations. This can greatly simplify client server communication, interacting can be done simply using straightforward JavaScript instead of having to build your communication for CRUD actions. In addition, Dojo data stores can plugin to many Dojo widgets (Dijits).

Complex database driven widgets can be utilized with minimal coding effort. RESTful JSON is an increasingly popular database interface, and in later posts we will look at how JsonRestStore can be used with Amazon S3, CouchDB, Persevere, and Ruby on Rails. The JsonRestStore fully implements the Dojo Data read, write, notification, and identity interfaces. Therefore it can be used with any widget that can utilize these data stores including widgets with editing and live auto-updating features.

Also new to Dojo 1.2 is the ServiceStore. JsonRestStore is an extension of ServiceStore. ServiceStore provides Dojo Data read and identity interface for remote web services. However, I will primarily focus on the JsonRestStore in this article.

Using a JsonRestStore

The JsonRestStore can be created with a REST service function, or it can be instantiated directly with a target URL. To get a JsonRestStore instance with a target URL:

recipeStore = new dojox.data.JsonRestStore({target:"/recipeStore"});

A JsonRestStore can be created from a REST service function which can be generated with dojox.rpc.Service:

services = dojox.rpc.Service("/mySMD");
recipeStore = new dojox.data.JsonRestStore({service:services.myRestService});

jsonrest-servicestore.png

Fast and Compact Syntax

While you can use JsonRestStore and ServiceStore as you would another data store, they have been designed to support a more compact syntax for data interaction as well. This can be very beneficial if you have extensive code that interacts with the data store. First, several of the commonly used store methods are available as “static” functions, including getValue and setValue. Therefore we can easily define a convenient global or local functions for common operations.

The get, set, and save functions can be used with multiple JsonRestStore stores; it is not limited to the JsonRestStore from which it was retrieved.

With a few simple guidelines, you can actually interact with JsonRestStore items using standard JavaScript property syntax. JsonRestStore items are actually simple JavaScript objects, therefore you can always directly read properties from items.

get = recipeStore.getValue;
set = recipeStore.setValue;
save = recipeStore.save;
... // fetch an item
get(item,"foo"); // instead of using recipeStore.getValue(item,"foo");
set(item,"foo","bar"); // instead of using // recipeStore.setValue(item,"foo","bar");
save();
value = item.foo;
// instead of calling value = recipeStore.getValue(item,"foo");
var prop = "baz";
anotherValue = item[prop];
// instead of calling value = recipeStore.getValue(item,prop);

You can also modify properties of items using standard JavaScript syntax. However, in order for the JsonRestStore to know that an item has been modified, you must call the changing() method prior to modifying properties. Once you have called changing(), the object will be denoted as being dirty and you can make as many changes to the object (the object’s properties) as you want until you call the save() method. Once you call the save() method, you need to call changing() again before modifying an item again. Note, that it is safe to call changing() multiple times.

recipeStore.changing(item);
// mark item as dirty
item.foo = "bar";
// instead of calling value = recipeStore.setValue(item,"foo","bar");
item[prop] = 4;
// instead of calling value = recipeStore.setValue(item,prop,4);
recipeStore.save();
// this always must be called to commit the changes,
// regardless of whether you use setValue or not.
Property Access Performance Comparison

Browser Direct
Property
Access
JsonRestStore
getValue
ItemFileReadStore
getValue
FF3 0.037µs 1.44µs 6.3µs
FF2 0.047µs 1.75µs 9.1µs
Safari3 0.055µs 1.10µs 4.1µs
IE8 0.28µs 3.0µs 13.7µs
IE6 0.28µs 5.0µs 21µs

If you are writing extensive code based on a data store, this can make your code much more compact, readable, and maintainable. In addition, there are significant performance benefits from direct property access. Property access is 10-50 times faster than using getValue. For large or computationally intense use of data stores, direct property access may be very important for optimal performance.

There are a couple of things to remember with direct property access. First, setting properties directly does not trigger notifications. Since setting properties is usually much less frequent than reading properties, it is recommended that in most situations that you only use direct property access for reading, and use the standard simple setValue (or a convenience copy) for writing.

Also, the JsonRestStore architecture supports lazy loading using JSON referencing. When a value is accessed that is referenced, but not yet loaded, the property value can be tested with the isItemLoaded function. You can load and access the value by calling the loadItem function. You can also use the standard getValue method (or a copy of it as demonstrated above) in situations where the property may be lazy, and the getValue method will automatically download the value on demand. If you are not using JSON referencing and lazy loading you can always directly access properties using normal JavaScript syntax. However, if you are using lazy loading, when a property value is a lazy loaded you can test for values that have not been loaded and load them asynchronously:

myValue = item.foo;
if(recipeStore.isItemLoaded(myValue)){
	recipeStore.loadItem({item:myValue,onItem:function(result){
		... resume with result ...
	}});
}

or simply using synchronous loading (for lazy loaded properties, the Dojo Data getValue function is the easiest form of access):

myValue = recipeStore.getValue(item,"foo");

Remember, this is only necessary if you are using lazy loading via JSON referencing. Also, using direct property access is purely optional, you can use the JsonRestStore with the same API as any other Dojo Data store.

JsonRestStore also provides a constructor for aesthetic creation of new objects. This constructor is accessible with the getConstructor method:

Recipe = recipeStore.getConstructor();
// create a new recipe object instead of recipeStore.newItem();
var recipe = new Recipe();

The constructor also includes a load function for convenient access to the Rest service querying and fetching items by id.

Now we can put this all together, If we first create aliases for getValue, setValue, save, and changing and then create the Recipe constructor we can write:

// make Apple Pie
var query = Recipe.load("?type='Pie'"); // query for the recipes for pie
query.addCallback(function(queryResults){ // when the results are returned
	var recipe = queryResults[0]; // get the first result
	if(recipe){
		if(recipe.name!="Apple Pie"){ // get the name property
			changing(recipe); // indicate we are changing properties
			recipe.name = "Apple Pie"; // rename this recipe to apple pie
		}
	}else{
		// create a new Recipe for apple pie
		recipe = new Recipe({name:"Apple Pie"});
	}
	save(); // save our changes to the database
});

JsonRestStore and ServiceStore also support synchronous mode. Synchronous requests can create a poor user experience since they generally lock up the browser while the browser waits for a response from the server. However, synchronous mode can also simplify programming. Since it is not necessary to use nested callbacks for handling responses, they can be accessed directly after making a request inducing call. Firefox 3 has also eliminated the browser lock-up associated with synchronous calls, making it a more attractive mechanism. To use synchronous mode, you include the syncMode option when instantiating a data store:

recipeStore = new dojox.data.JsonRestStore({target:"/data",syncMode:true});

In synchronous mode, one can fetch without providing a callback, by directly accessing the results property from the request object that is returned from the fetch operation:

var queryResults = recipeStore.fetch({query:"?tastes='good'"}).results;
var firstItem = queryResults[0];

Implementing a RESTful JSON Server

The JsonRestStore can be used with a number of server storage systems that support HTTP JSON/REST interface without any server-side coding. Several JsonRestStore extensions designed to easily connect with Persevere, CouchDB, and Amazon S3 with minimal configuration are included with Dojo 1.2. You can also easily create your JSON/REST interface for an existing web application and database. This is essentially done by implementing the HTTP methods GET, PUT, POST, and DELETE according to the HTTP specifications and providing the data in JSON format. While the JsonRestStore can be configured (using dojox.rpc.Service) to support other configurations, generally rows/items/objects should be accessible using URLs of the form /table/id. GET is used to retrieve objects and perform queries, POST is used to create new objects (by POSTing to /table/), PUT is used to modify objects, and DELETE deletes objects. You can also follow the example used by other JSON/REST interfaces like Persevere and CouchDB.

Transactions

JsonRestStore provides transaction state information so that servers can implement transactions that correspond to the Dojo Data it saves if desired (this is not necessary for a server to implement in order to support REST). Transactions are indicated by a X-Transaction header in the modifications requests. If the X-Transaction header has a value of open, this means that further requests will be delivered that should be included in the current transaction. Once a request is received without an X-Transaction header of open, the server can commit all the changes from the current request and the previous requests that indicated an open transaction. It is recommended that you utilize deterministic request ordering and page sessions if you implement JsonRestStore directed transactions on the server.

JsonRestStore also features a shared repository of transactional data between all JsonRestStore instances. Therefore, if you save a change, all the JsonRestStore data store’s unsaved data will be committed. This means that you don’t have to track which data stores have modified data, and it also means that you transactions can involve modifications across multiple data stores and corresponding server tables.

Build with, not on JsonRestStore

The JSON REST infrastructure is composed of a layer of modules that can easily be utilized and extended on their own, following the Dojo philosophy of extensibility. First, JsonRestStore is an extension of the ServiceStore data store and is designed for provider/store separation. The ServiceStore is a read-only data store built such that various different remote data providers can plugin to the ServiceStore. Thus the ServiceStore provides an adapter between the remote communication provider and widgets. Within dojox.rpc, several commonly used remote communication plugins are provided including REST, JSON-RPC (version 1 and 2), JSONP, and direct POST and GET. You can also easily create custom remote data providers, by creating a service function that takes parameters and returns a dojo.Deferred object that will receive the result of the query. These can all be used with the ServiceStore. The demonstration of using ServiceStore with a Yahoo search web service shows this in action. You should use the ServiceStore whenever you are working with a read-only web service (that doesn’t support full bi-directional REST), as it is lighter than JsonRestStore.

yahoo-search-demo.png

ServiceStore only provides read capabilities (the Dojo Data Read API), however, writable remote communication providers (REST services) can plugin to the JsonRestStore for full read-write capability. A writable provider is one that provides put, post, and delete functions as properties of the main retrieval function. Once again, you can use the HTTP/REST compliant provider included with Dojo (dojox.rpc.Rest) or you can create your own.

Build with REST Infrastructure

dojox.rpc.Rest can also be used directly. A REST service can be constructed with dojox.rpc.Rest:

var restService = dojo.rpc.Rest("/myRestTarget",true);

This indicates that the rest service can be found at /myRestTarget and it is a JSON service, which enables additional caching and optimization capabilities. You can retrieve data from this service:

restService("10") // retrieve the object with an id/resource location of 10

This would result in a fetch from the local resource /myRestTarget/10. You can modify this resource with a PUT:

restService.put("10",{foo:"bar"});

This will store the provided JSON object into the target resource. You can also use restService.post and restService.delete to further directly modify resources. JsonRestStore uses these access points to persist all data changes in the data store. New objects are added with a service.post, deleted objects are removed with a service.delete and modifying objects are updated with a service.put.

jsonrest-infrastructure.png

The dojox.rpc.JsonRest module is the core engine behind JsonRestStore. JsonRest can be used directly, providing a compact API with the core features of JsonRestStore, including transactional data interaction and query and object loading. dojox.rpc.JsonRest is a singleton object, and provides functions: fetch, commit, revert, changing, deleteObject, getConstructor, and isDirty. These correspond to the same functions on JsonRestStore, but the single JsonRest object can be used without requiring separate data stores to be used to access the API. If you do not need the Dojo Data API, and you only need JSON/REST interaction, you can go lighter, and directly interact with dojox.rpc.JsonRest. However, because the Dojo Data API enables you to plug stores into numerous widgets with minimal effort, generally using JsonRestStore is preferable to directly using JsonRest.

JsonRestStore also has comprehensive referencing capabilities, including circular, multiple, and cross-store, and cross-site references. This feature is also provided by a separate JSON referencing module, dojox.json.ref for modularity and extensibility. Therefore, you can use the JSON referencing module to resolve and serialize references for data exchange outside of JsonRestStore. For example, you could easily use referencing for JSON-RPC data, and even allow RPC parameters and return values that reference data from REST stores. This modular structure also allows you to extend or use alternate referencing conventions for JsonRestStore.

Live and Offline Data Stores

Because the JsonRestStore uses the extensible Rest service, JsonRestStore also works with HttpChannels, the new cometd transport/protocol module, to provide a Comet-powered real time view of data on a server. This does not require writing any additional event handlers. If you are using a server that supports HTTP Channels (like Persevere), you can simply add the HttpChannels and you can will have a live view of your data. Be sure to check out the JsonRestStore in action with live updates.

Likewise, JsonRestStore will also run in offline mode by simply adding the forthcoming dojox.rpc.OfflineRest module. The OfflineRest module augments the REST service. As a result, a JsonRestStore running off of a REST service will automatically be able to run in offline mode, with data changes saved locally when offline and automatically re-synced when connectivity is restored.

Dojo 1.2 now has a comprehensive infrastructure for RESTful interaction with servers. JsonRestStore is a modular data store with built in capabilities for interacting with servers in standards-based manner that already works with a number of existing server technologies, and provides a widely usable data store for server side storage that is easy for servers to interact with. Stay tuned for more posts on using JsonRestStore with various storage servers.

Comments

  • Hi, nice post. To see how to integrate with Jackrabbit have a look here: http://dev.day.com/microsling/content/blogs/main/dojosling101.html

    Cheers
    Michael

  • Michael,
    Yes, I have seen Sling’s data store. Do you think the Sling server is REST/HTTP compliant enough (and in JSON) to work with the JsonRestStore? I would love to be able to connect to Sling if possible.

  • Pratik Patel

    Where is this mystical Dojo 1.2 release? http://download.dojotoolkit.org/ turns up 1.1.1 as both the stable and development release… even google can’t find it!

  • Dojo 1.2 will be released in July. For now, you can head to http://archive.dojotoolkit.org/nightly/ to download the latest Dojo pre-1.2 snapshot.

  • Pratik Patel

    looking forward to the release, jsonreststore and a few other things look really cool!

  • Pingback: Medryx Observations » Blog Archive » Pseudo-RESTful()

  • Pingback: Medryx Observations » Blog Archive » An Object-Relation-Mapper (ORM) for Javascript? Well, kind of…()

  • Vilas

    Do you an example of how REST / JsonRestStore can be used to read/write/update/delete items stored in a grid? It will be really helpful.

  • Vilas,
    I would gladly do a post with more comprehensive examples of using JsonRestStore with widgets, but briefly it is as simple as plugging the store into a grid and then the standard Dojo Data API commands will auto-update the grid. For example:
    <table dojoType=”dojox.grid.DataGrid” store=”recipeStore”> … table headers … </table>

    And then:
    recipeStore.deleteItem(item) // will remove a row from the grid
    recipeStore.newItem(item) // will create a new row in the grid
    recipeStore.setValue(item,prop,value) // will update a row in the grid

  • Pingback: SitePen Blog » Amazon S3 + Dojo()

  • Pingback: Comet Daily » Blog Archive » Dojo HttpChannels Module()

  • Steven

    This is a great ! Dojo is absolutely the pioneer implementing the new technologies.

    I just tried to use the JsonRestStore with the tree model and dijit.tree. It looks it is not as simple as just plugging it to dijit.tree. Some massage seems needed, but I could not figure it out. Could you talk about it in your next post regarding JsonRestStore?

    Good job !

  • @Steven: I can try to include instructions for using it with a tree in the next post about JsonRestStore. However, I think the primary prerequisite for the tree is that the items/objects in the JsonRestStore have a “children” property that has an array of the list of children.

  • steven

    Kris, thanks for the reply. I also find the lazyloading feature does not work properly. The code is like this:

    var store = new dojox.data.JsonRestStore({target: “/something/”});
    var args = {
    query: 1, // it does generate url like GET “/something/1”
    onItem: function(item){
    console.debug(“item is ” + item.label)
    },
    onError: function(err){
    console.debug(“error occured “)
    }
    };
    var item = store.fetch(args).results;

    The json sent back from server is like:
    { “id”: 1,
    “parentId”: 0,
    “label”: “something_1”,
    “type”: 1,
    “children”: [
    { “$ref”: “3”},
    { “$ref”: “5”},
    { “$ref”: “7”}
    ]
    }

    // get first referred object
    var kid = store.getValue(item, “children”)[0]

    It does NOT issue a xhr call to lazy load the referred objects.

    the properties of kid is like:
    Methods: _loadObject
    Fields: $ref, __id

    I check that store.loadLazyValues has been set to true.

    Also, the usage of store.fetch and store.byId(aliased to fetchItemByIdentity) are confusing. For example, the query to store.fetch , like {query: 1}, generates the same url(/something/1) as store.byId({identity: 1})

    I feel I had mistakes using store. It would be great if some documents are available.

    Thanks

  • @steven:
    JsonRestStore does not do recursive loading of all children when you do a getValue. In the example, store.getValue(item, “children”) returns an array that is loaded, but the children (array items) of the array are not loaded. You should be able to do:
    store.getValue(store.getValue(item, “children”),0);
    Of if you know that children is not lazy, as in your example you can simply do:
    store.getValue(item.children, 0);
    Or alternately you can avoid synchronous calls:
    store.loadItem({item:store.children[0],onItem:function(loadedChild){
    ….
    });
    All of these should trigger a request for “3”.

  • @steven:
    Also, in regards to byId behaving the same way as query, this is by design. JsonRestStore is intended to be query string agnostic, you can use any query string style you would like, both queries and identity lookups simply map to URL requests.
    Also, the last example from my last comment had a typo, it should be:
    store.loadItem({item:item.children[0],onItem:function(loadedChild){
    ….
    });

  • Pingback: SitePen Blog » Getting Started with Persevere Using Dojo()

  • Pingback: REST and TG at Compound Thinking()

  • steven

    Kris, super good reply ! Another question. The result from asyn fetch should be accessed via the deferred object that containing the returned result. In JsonRestStore, the only way, I find so far, to get that deferred object is from the store.getConstructor.load method, like the following code in your blog

    var query = Recipe.load(“?type=’Pie'”); //query is the deferred obj

    To get the deferred object for returned data is important in asyn mode. Is there any other obvious(I mean ‘obvious’ by comparing to the load method hidden somewhere) way to get it?

    Many thanks.
    Is there any other way to get that deferred object?

  • @steven: With the JsonRestStore you can use the fetch according the dojo.data.api.Read API (http://api.dojotoolkit.org/jsdoc/dojo/HEAD/dojo.data.api.Read.fetch) for async loading, for example:
    store.fetch({query:”?type=’Pie'”,onComplete:function(results){

    });

    fetch doesn’t return a Deferred object because fetch includes support for progressive loading and Deferred doesn’t.

  • I’ve written up my take on JsonRestStore and using it for non-REST web services. Hope its helpful to someone!

    http://blog.medryx.org/2008/07/24/jsonreststore-overview/

  • steven

    Kris, I find a problem of using method newItem. Let’s say:

    store.newItem(data, parentInfo);
    store.save();

    The new item is added to store with a random number in place of id of ite __id propery, like this:

    “__id”: “/resource/99e23f01ac40c7d883b01818”

    This value of ‘__id’ property will be used as the url for the further xhr request upon any update(editing, or adding its children item) to this new item. The random number in __id is done on purpose in the source code. I guess this intends to leaves the chance to user to replace the new item’s id with “actual” id, while the “actual” id should be determined by server and derived from the returned new item from server.

    This is perfect due to this flexibility its leaves to user. However, I could not find it any where on how to have the replacement of values of “actual” id and __id take place. One place I realized is the function onPostCommit, which seems to aim for this purpose but it is not been implemented (I already file a bug report in trac for onPostCommit).

  • onPostCommit is intended to be implemented by subclasses (it is ignored otherwise). I can update JsonRestStore? to update objects based on the ids assigned by the server (per the HTTP spec, this should come from the Content-Location header). However, I have been hesitant to code this because it is such a fragile solution. If you create a new item and save it (triggering a POST), and then make a modification and save it before the first save’s response is received, it is impossible for the JsonRestStore? to know the assigned id. It would be possible to delay the second save until the first save is received, but this would significantly increase the size and complexity of the code, so I will surely avoid this solution. There is also additional complexity because we can’t change the client reported id (from getIdentity(item)) or it will break widgets, so must retain the client assigned id for getIdentity calls. Consequently, I believe it is better for the server to maintain a session based temporary map of client ids that map to the assigned server ids. However, I can still code this change for those that want to use it.

  • kirlian

    Hi,

    If we have 2 jsonreststore, how to update only one ?

    Arnaud.

  • @kirlian/Arnaud: The JsonRestStore has been designed to treat transaction like databases do, transactions are not local to a single table or store, but span table/stores. If there is a desire to have commits that only affect a single JsonRestStore, I can add a configuration setting to support that option. I would love to know what the use case is that demands such an option though.

  • kirlian

    Hi,

    Thanks for your answer.

    The main subject is the order of the transactions. How can we say to 2 jsonrestore that an insert or update must be done first on this table and second on another table ? And in case of deletion this is the opposite ? The workflow in the screen to key in data can be different from the workflow to insert data in the database.

    If we take as example a screen wich display an order.

    There is two sections : the first one with the entity data (name of supplier, order date…) and one grid with the detail of article.

    In that case, there is one jsonrestore for the entity data and one for the grid.

    To create a new order, the entity must be created before the details in the database to respect database constraints. If we have two controllers “entity_order” and “detail_order” how to do without having commits that only affect a single JsonRestStore ?

    Arnaud.

  • @Arnaud: I just checked in a fix for JsonRestStore, it should now default to saving only the data for that particular store (but you can still global saves with the “global” option).

  • kirlian

    Hi,

    Thanks for this fix, it was really important according to me.

    If I can suggest you another enhancement : to allow to commit for a jsonreststore only updated items, deleted items or created items.

    Usually when you have 2 tables linked, the order to make the insert is the opposite than the order to make the delete and their is no order for the update.

    Arnaud.

  • Pingback: JSON » Blog Archives » Dojo 1.2 Beta Available()

  • ben hockey

    i’m having a problem getting this to work. to avoid filling up your blog, i posted in the forums – http://dojotoolkit.org/forum/dojox-dojox/dojox-support/jsonreststore-expected-data-format-0 could you take a look at it for me?

    thanks.

  • steven

    Krys,

    Your modification to JsonRestStore regarding onPostCommit is exactly what we need. Thanks !

    Here is another question which might look silly…

    When testing JsonRestStore, in the smd file:

    {
    services: {
    jsonRestStore: {
    transport: “REST”,
    envelope: “URL”,
    target: “fakeserver.php”,
    contentType:”application/json”,
    parameters: [
    {name: “location”, type: “string”, optional: true}
    ]
    }
    }
    }

    In the target property, where to put fakeserver.php file. Is it relevant to the smd file, or it has to be a full path of url(which means the web server needs to be up, but this seems to break the rule of cross-domain access)?

  • @steven: The URLs in the SMD are relative to the SMD file, so it is fine to do:
    target: “fakeserver.php” or target: “/fakeserver.php”.

  • Pingback: SitePen Blog » Effortless Offline with OfflineRest()

  • steven

    Hi Kris,

    The fakeserver.php just works for me. Thanks ! Two more questions.

    In dojox.rpc.JsonRest, starting at line 84:
    var newId = dfd.ioArgs.xhr.getResponseHeader(“Location”);
    if(newId){ object.__id = newId;
    var objectId = newId.match(/\/([^\/]*)$/);
    if(idAttr && objectId){
    object[idAttr] = objectId[1];
    }
    Rest._index[newId] = object;
    Should the server set the header[“location”] with the prefix of servicePath for newId? Because Rest._index is shared by all stores, the newId should have servicePath as prefix, otherwise it would mess up Rest._index. Is this correct?
    Why is __clientId not set with newId in the same time? In JsonRestStore.js, the function getIdentity checks the property of __clientId.
    getIdentity: function(item){
    var id = item.__clientId || item.__id;
    more codes …}

    If the new item does not get refreshed by being reloaded from server, __clientId of the new item would remain like /service/path/78dafd6899, and therefore getIdentity would get the wrong id of the new item.

  • @steven: JsonRestStore expects the Location header should to be an absolute path, like that the absolute paths used by __id (“/table/id”).
    getIdentity() must always return the same value for a given item. This is an invariant that many widgets rely upon. The reason for the __clientId property is so that even after the id is updated, getIdentity() can still return the same value. If getIdentity() changes its return value widgets like the Grid will break.

  • Pingback: SitePen Blog » CouchDBRestStore()

  • Pingback: SitePen Blog » Jaxer + Persevere via Dojo’s JsonRestStore()

  • Pingback: Medryx Observations » JsonRestStore — Custom Services, Schemas, and Lazy Loading()

  • Pingback: Release Notes zum Dojo Toolkit V1.2 - dojotoolkit-forum.de()

  • Great post. I tried to build this but the grid wont’ show the data with the JsonRestStore. Here’s a piece of code :

    var Service = function(query, queryOptions) {
    return dojo.xhrGet({url:”/test/”, handleAs:”json” }); }
    Service.post = function(id, value) {
    return dojo.xhrGet({url:”/test/”, content:{method:”create”, id:id, value:value}}); }

    store = new dojox.data.JsonRestStore({target:”test”, service:Service});

    // the grid
    dojo.addOnLoad(function(){

    // set the layout structure for the grid version 1.2
    var layout4 = [
    { name: “Test”, field: “post_id”, width: ’40px’},
    ];

    // create a new grid:
    var grid4 = new dojox.grid.DataGrid({
    query: { post_id: ‘*’ },
    store: store,
    structure: layout4,
    }, document.createElement(‘div’));

    dojo.byId(“gridContainer4”).appendChild(grid4.domNode);
    grid4.startup();
    });

    Now, /test/ returns this data format :

    [
    {“post_id”:”1″,”user_id”:”1″,”url”:”new-post”,”ts_created”:”2008-10-01 14:16:30″,”status”:”Live”,”profile_key”:”title”,”profile_value”:”new post”},
    {“post_id”:”2″,”user_id”:”1″,”url”:”new-post-draft”,”ts_created”:”2008-10-01 14:17:38″,”status”:”Draft”,”profile_key”:”title”,”profile_value”:”New post draft”},
    {“post_id”:”20″,”user_id”:”1″,”url”:”test-3″,”ts_created”:”2008-10-01 22:28:46″,”status”:”Draft”,”profile_key”:”title”,”profile_value”:”test”}
    ]

    I tried also to return another data format that worked using IwriteFileStore that I tried, but that got me nowhere :

    {“identifier”:”post_id”,”items”:
    [{“post_id”:”1″,”user_id”:”1″,”url”:”new-post”,”ts_created”:”2008-10-01 14:16:30″,”status”:”Live”,”profile_key”:”title”,”profile_value”:”new post”},
    {“post_id”:”2″,”user_id”:”1″,”url”:”new-post-draft”,”ts_created”:”2008-10-01 14:17:38″,”status”:”Draft”,”profile_key”:”title”,”profile_value”:”New post draft”}
    {“post_id”:”20″,”user_id”:”1″,”url”:”test-3″,”ts_created”:”2008-10-01 22:28:46″,”status”:”Draft”,”profile_key”:”title”,”profile_value”:”test”}]
    }

    Do you have any idea of what’s going wrong ?
    The grid does not display anything…

  • The problem is that you didn’t specify an identity attribute, and
    JsonRestStore defaults to “id” as the identity property (and it
    doesn’t use the ItemFileReadStore format). You can specify the
    identity attribute in the JsonRestStore constructor:

    store = new dojox.data.JsonRestStore({target:”test”, service:Service,
    idAttribute:”post_id”});

  • Pingback: Comet Daily » Blog Archive » Using Bayeux with Persevere()

  • Tim

    Great post!

    Is it possible to use the JsonRestStore with a local json array? In other words if I have a json array returned from somewhere already. This came up when I was trying to use thr new grid with OpenLayers a JS mapping api. OL has it’s own callback mechanism and I was able to get my map server to return a json array. Then I could not figure out a way to get the json into a grid.

    Will this control do that or is there another way?

  • If you have your own callback mechanism that could be called and return json, you can provide that as a service to JsonRestStore (http://blog.medryx.org/2008/07/24/jsonreststore-overview/). However, JsonRestStore’s fetch relies on calling something to get data, so if can’t provide a json data provider, you can’t instantiate JsonRestStore with a predefined set of data. If you want to do that, you probably want the ItemFileReadStore.

  • Tim

    How do I tell the ItemFileReaqdStore to read an in memory array as instead of a file?

  • I believe that is done like this:
    inMemoryArray = [{name:”item 1″},….);
    new dojo.data.ItemFileReadStore({data: {items: inMemoryArray}});

  • Pingback: Comet Daily » Blog Archive » Using REST Channels in Dojo()

  • Pingback: SitePen Blog » Effective use of JsonRestStore: Referencing, Lazy Loading, and more()

  • Pingback: SpringOne 2008 Day 4 « Incremental Operations()

  • philou

    Hi,

    just because it took me hours to find my coding mistake, here a working example of the JsonRestStore:

    exampleJsonRestStore.html :

    //

    Json Rest Store example

    //

    The request “sendmeJson.php” returns:

    [
    {"uid":"1","user_full_name":"Joe"},
    {"uid":"2","user_full_name":"Doe"},
    {"uid":"3","user_full_name":"Shmoe"}
    ]

    Hope that helps,
    p.

  • philou

    Hi, just because it took me hours to find my coding mistake, here a working example of the JsonRestStore: exampleJsonRestStore.html :

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html&gt; <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <style type="text/css"> <!– @import "scripts/dojo-1.2.2/dijit/themes/tundra/tundra.css"; @import "scripts/dojo-1.2.2/dojox/grid/resources/tundraGrid.css"; @import "scripts/dojo-1.2.2/dojox/grid/resources/Grid.css"; –> </style> <script type="text/javascript" src="scripts/dojo-1.2.2/dojo/dojo.js"></script> <script type="text/javascript"> //<!– dojo.require("dojox.data.JsonRestStore"); dojo.require("dojox.grid.DataGrid"); //–> </script> <title>Json Rest Store example</title> <script type="text/javascript"> //<!– var userService = function(query, queryOptions) { return dojo.xhrGet({url:"sendmeJson.php", handleAs:’json’, content:{query:query, queryOptions:queryOptions}}); } userService.put = function(id, value) { myService.post(id, value); } userService.post = function(id, value) { return dojo.xhrPost({url:"actionUrl.php", handleAs:’json’, content:{action:"update", id:uid, value:value}}); } userService[‘delete’] = function(id) { return dojo.xhrPost({url:"actionUrl.php", handleAs:’json’, content:{action:"delete", id:uid}}); } var userStore = new dojox.data.JsonRestStore({target:"users", service:userService, idAttribute:"uid"}); dojo.addOnLoad(function(){ var userLayout = [ { field: "uid", name: "ID" }, { field: "user_full_name", name: "Full Name" } ]; userGrid = new dojox.grid.DataGrid({ query: { id: "*" }, store: userStore, structure: userLayout }, "gridNode"); userGrid.startup(); }); //–> </script> </head> <body class="tundra"> <div class="gridContainer" style=" height:350px;"> <div id="gridNode"></div> </div> </body> </html>

    The request "sendmeJson.php" returns: [ {"uid":"1","user_full_name":"Joe"}, {"uid":"2","user_full_name":"Doe"}, {"uid":"3","user_full_name":"Shmoe"} ]

    Hope that helps, p.

  • @philou: Was there a particularly pitfall that you found that could be better explained, documented, or warned about?

  • philou

    @Kris,

    first of all, please excuse my messy previous post, but I could not get the html to show AND have line breaks.
    Furthermore, the JsonRestStore may seem really easy to use to many here, but I was stuck at a similar point as Zladivliba above trying to get the JsonRestStore to feed a dojox.data.Grid. I felt I did everything right and nothing was working ;-)

    I mostly used your tutorial here and that of Medryx (http://blog.medryx.org/2008/07/24/jsonreststore-overview/) to piece my script together. Since there was no “test.html” in dojo 1.2.2. for JsonRestStore (or did I just not see it!?!), it took me literally hours to get a JsonRestStore running with just any configuration.

    In my case the missing bit was that I did not call grid.startup() after declaring the grid – something that was apparently not necessary to get the dataGrid to work with ItemFileReadStore which I had used before.

    So I felt it might be useful to have a complete example with html, javascript and json data, that can be used to get the JsonRestStore to run and then make little modifications to see at what point it breaks, to figure out why a particular setup isn’t doing what you want it to.

    In fact, I still don’t understand some of your code snippets relating to an “item”:
    get(item,”foo”);

    Where do you get the “item” from when it is not passed to you by an event? Say, to have a button that deletes a particular item, how do I identify it?

    Thanks for all your help!
    p.

  • Pingback: The 12 Patterns for User Interface Design « Seen through my Eyes()

  • miso

    Hi, would it be possible to have an example of how to enable server side sorting for JsonRestStore + Grid (in my case the data that will be managed by the grid is too big to be loaded at once and use dojox.data.ClientFilter).
    It seems that by default no sort information is sent to the server when a grids column header is clicked.

  • @miso: Because there is no standardized way of indicating a sort with HTTP, JsonRestStore doesn’t create any parameters for sorting by default in the generic class. There are a couple options:
    You can override your store’s fetch method to handle sorting:
    store.fetch = function(args){
    // however you want to convert the sort attributes to a query:
    args.query += “sort=” + args.sort[0].attribute;
    return this.inherited(arguments);
    }

    Also, if you can use nightly/beta 1.3, you could use the JsonQueryRestStore. This can be used without ClientFilter, and it will convert all query information (sorting, paging, name-value pairs) into a JSONQuery expression in the URL, which can be handled by your server.

  • Pingback: SitePen Blog » New in JsonRestStore 1.3: Dates, Deleting, Conflict Handling, and more()

  • RoryD

    I have one problem with the .newItem()/.savee() sequence when used with widget(Tree in this case). Calling newItem() creates an item client-side which triggers a callback to onNew() on the TreeStoreModel, causing the Tree to attempt to refresh itself.

    This causes the tree to re-request its contents, but it doesn’t find the new item since save() has not yet been called. Do I have to manually refresh the tree after calling save (in the onComplete handler passed to save)?

    It seems to be that either onNew should only be called after a save() call, or it should at least be called again after save(). Am I missing something here?

  • @RoryD: Widgets that issue fetches while there is uncommitted data do pose a challenge for the JsonRestStore, because their is no mechanism for the JRS to reliably send uncommitted changes to a server via HTTP (using RFC 2616). There are a couple of ways to deal with this. You can use the ClientFilter mixin with JRS or JsonQueryRestStore (a subclass of JRS) to provide client side caching of data so that fetches will be handled on the client side with the uncommitted data properly handled (http://www.sitepen.com/blog/2008/12/18/more-query-and-caching-power-for-data-stores-clientfilter-jsonquery-and-jsonqueryreststore/). Or you, could add a listener to the notification events (onNew in this case) and call save() so that the data change is sent to the server before the fetch request is sent to the server.

  • Jesus Diaz

    Hi Kris,

    I’ve been working for a while with dojo, integrating it to existing and new .Net applications I’m developing. Currently, I’m trying to implement a ServiceStore to connect to an .Net web service. If the service is local to the site, I have no problem at all. On the other hand, if the service is defined in a different project, I got an access denied error. Reviewing the examples of Yahoo, Google and Wikipedia integration, it seems to me it is possible to consume a .Net service defined elsewhere.

    I could send you snapshots of the service, Store and page if you are interested in helping me.

    Regard,

    Jesus Diaz

  • @Jesus:
    In order to access a cross-domain web service from the browser, you must use a cross-domain transport. If you are using an SMD-driven web service, you should probably use the JSONP transport (you can see the yahoo.smd for an example). Alternately you can add cross-domain capabilities using the cross-domain XHR registry (http://www.sitepen.com/blog/2008/07/31/cross-site-xhr-plugin-registry/), but this will still require the use of JSONP or window.name transport in order to communicate with the non-origin server.

  • taras

    @Jesus
    Could you please share your experience in implementing JsonRestStore on .Net ? I’m struggling to build something similar on top of an existing web framework: [http://code.google.com/p/n2ims/]. It feels like there’s a vacuum as to the information on how to implement a REST-full access to a hierarchical data source. Yet i see the Dojo/JsonRestStore/Persevere stack as a best example to follow..

  • mike

    Does anyone have a working example of dijit.tree, dijit.tree.TreeStoreModel and JsonRestStore and a sequence of json coming from the backend?

    I can get the tree to request the root node and put the json in the store, and into the model and then into the tree. It then retrieves the first set of children (by reference), the json is received OK, but it doesn’t put it into the store (at least it doesn’t appear in the tree).

    Do I have to set a “parent” attribute on the json coming back?

  • chris

    @mike
    This might help get you started.

    I have a question of my own:
    The onNew and onDelete events don’t get popagated from the restStore to the model, in the case of newly downloaded tree nodes. The store itsself works fine. It just doesn’t show up on the tree.
    What am I missing here?

    Delete
    New Class
    New Object

    this.inherited(“pasteItem”, arguments);
    var oldChildrenList = classModelTreeStore.getValues(oldParentItem, ‘children’);
    classModelTree._onItemChildrenChange(oldParentItem, oldChildrenList);
    var newChildrenList = classModelTreeStore.getValues(newParentItem, ‘children’);
    classModelTree._onItemChildrenChange(newParentItem, newChildrenList);

    var menu = dijit.byId(“classModelTreeMenu”);
    menu.bindDomNode(this.domNode);
    dojo.connect(menu, “_openMyself”, this, function(e){
    _selectedTreeItem = dijit.getEnclosingWidget(e.target).item;
    });

    if (this.tree.id==”classModelTree”) return true;
    return false;

    if(source.tree && source.tree.id == “classModelTree”) return true;
    //var mine = classModelTreeStore.getValue(source, “mine”, true);//should be false by default
    //var item = dijit.getEnclosingWidget(node).item;
    return true;

    if(!item) return “xxx”; // top level
    return classModelTreeStore.getValue(item, “852”, “unnamed”);//Label

    if(!item) return “class”; // top level
    var iconNr = classModelTreeStore.getValue(item, “856”, “0”);
    if(iconNr==1) return “object”;
    return “class”;

    _selectedTreeItem = item;
    var pageId = classModelTreeStore.getValue(item, “pageId”, “703”);//class model page
    checkForUpdates(‘mainpage’);
    var id = classModelTreeStore.getValue(item, “id”);
    var href = ‘nqserver/page.html?pageId=’+pageId+’&id=’+id;
    dijit.byId(‘mainpage’).setHref(href);
    document.title = “NQ – “+classModelTreeStore.getValue(item, “852”, “”);
    dojo.back.addToHistory( {changeUrl : pageId+’.’+id});
    this.inherited(“onClick”,arguments);

    The first call to the server gives this response:

    [{“854″:0,”852″:”root”,”856″:0,
    “children”:[{“$ref”:”844\/20″},{“$ref”:”844\/244″},{“$ref”:”844\/102″},{“$ref”:”844\/438″}],
    “id”:”1″}]

    The second call the the server gives this response:

    {“854″:0,”852″:”relationships”,”856″:0,
    “children”:[{“$ref”:”844\/249″},{“$ref”:”844\/2″},{“$ref”:”844\/5″},{“$ref”:”844\/250″}],
    “id”:”20″}

    and so on…

  • chris

    @moderator
    My previous post got screwed up due to html mark up.
    Please let me know how to fix.
    Chris

  • Nancy

    Hi Kris,

    I am relatively new to data stores. And was wondering when we create new store using recipeStore = new dojox.data.JsonRestStore({target:”/recipeStore”});

    Does it need to map to the backend class exposed at path ‘recipeStore’ and I am guessing that class needs to expose the GET,PUT, POST and DELETE calls?

    As there is no test html for JsonRestStore, it would really help if you could provide one. The previous posts included a sample but dint mention what they were doing in the php files. Can you eloborate more in case of Java classes at the backend?

  • @Nancy: The core documentation for JsonRestStore provides more information on what is required of the server:
    http://docs.dojocampus.org/dojox/data/JsonRestStore

  • Roland

    Hi Kris, why does the store append a trailing slash to the target I provide?

  • Roland Barcia

    Seems like my comment was deleted. Any reason why the URL pattern adds a trailing Slash. I would imagine that should be left to the developer?

  • J-R

    Hi,
    I’ve been having problems for a week with JSONRestStore and dijit.tree. I tried posting to dojo-interest but with no luck. I’m trying to build a tree that lazy loads. When I run my application however I get some nasty “too much recursion” errors. I have the url
    http://host/treerest/nodes/ that returns to me the root nodes.
    In this root nodes JSON structure that is returned I have a $ref to the children.

    I don’t know the ids of the children so if for instance the root nodes are 0 and 40. I create the ref with the format http://host/treerest/id/40 and http://host/treerest/id/0 which will respectively return the CHILDREN of nodes 0 and 40 when clicked.
    I have two questions:
    My first question is why is there a “\” that is added to my JSON.

    The second one is why do I get those too much recursion errors? Am I wrongly using the store? If yes can you please me how I should be using it properly? I am having a hard time finding non trivial examples for what I’m trying to do.
    Thank you kindly,
    JR

    To illustrate, here is the JSON that is initially returned:
    [{“scenario_id”:”1″,”node_id”:”0″,”node_type”:”scenario”,”node_name”:”Scenario1″,”children”:[{“$ref”
    :”\/treerest\/id\/0″,”scenario_id”:”1″,”node_id”:”0_1″,”node_type”:”stub”,”node_name”:”placeholder”}
    ]},{“scenario_id”:”2″,”node_id”:”40″,”node_type”:”scenario”,”node_name”:”Scenario2″,”children”:[{“$ref”
    :”\/treerest\/id\/40″,”scenario_id”:”2″,”node_id”:”40_1″,”node_type”:”stub”,”node_name”:”placeholder”
    }]}]

  • @J-R: I can discuss this more on dojo-interest, but briefly there is an example of using the JRS with the tree here:
    dojox/data/tests/stores/test_Tree_on_JsonRestStore.html

  • (dojox/data/tests/stores/test_Tree_on_JsonRestStore.html is in Dojo’s nightly build/trunk)

  • Freitags

    I have Problems to get the edited items back into my database.
    when I do this:


    var store = new dojox.data.JsonRestStore({ target:’/json’});

    var grid = new dojox.grid.DataGrid({ query:{}, store: store, structure: layout}

    And the layout has some editable fields, is the datagrid supposed to send post requests to the server with the json data attached when I edit the fields? Or do I have to extend the datagrid and/or the jsonreststore?

  • Darrell

    Hi Kris, why does the store append a trailing slash to the target I provide

  • Darrell

    I downloaded the lastest Dojo build and was able to resolve my issue by using

    allowNoTrailingSlash: true

    when constructing a new dojox.data.JsonRestStore

    apparently, the code was fixed to allow one to override whether a trailing slash should be included.

  • @Freitags: Are you calling store.save() after editing the fields?

  • Darrell

    I populated a DataGrid from a JsonRestStore.

    Then, when the user clicks on a row in the Grid, I get the values from the item and display then in a dialog for updating.

    When the user changes a field on the dialog, I invoke the setValue() on the data store, but it fails with the following:

    “parts is null
    [Break on this error] (404 out of range 17)” – dojo.js

    Any ideas?

  • Darrell

    thanks for the reply Kris..

    I have tried the following:

    store.changing(item);

    store.setValue(item, attrName, value);

    store.save();

    – It fails on store.setValue().

    I don’t seem to have this value is I am changing an item that I create via store.newItem(). It seems to only fail to call setValue for items that were loaded via the grid.

  • Darrell

    I still need help with my issue using setValue() – Any more ideas?

  • Darrell

    I traced the setValue() method of the JsonRestStore and it fails when performing..

    var store = item.__id ? dojox.data._getStoreForItem(item) : this;

    it fails on the statement: dojox.data._getStoreForItem(item)

    error is “parts is null”.

    But, I still don’t know why it is failing.

  • Darrell

    RESOLVED!!!!!

    Ok – looks like I found the issue:

    I had to remove idAttribute=”pkHardwareId” from the definition of the store.

    Apparently, having an id associated with the store causing other logic to execute, which I am not able to leverage based on how I have things defined.

    Removing the attribute resolve the issue and I am able to execute the setValue() method.

    The new values show in my grid, BUT…. only after I page forward and then backwards to redisplay the item. Of course, I would like for the change to display immediately.

    Maybe there is a refresh of some kind that i can do to immediately see the change from the store visible in the grid?

  • Darrell

    In FF my column headers and column do not align using the dojox.grid.DataGrid – But, all is OK in IE.

    Any ideas?

  • Darrell

    Resolved!!! – The issue I had in FF was related to some custom styles we were using.

  • Darrell

    I am using the DataGrid in version 1.3.2 and have a cell defined with type =dojox.grid.cells.DateTextBox. When I double click the cell to enter edit mode the calendar display with a default value of 12/31/1969. How can I change the default to the current date?

  • Darrell

    I am using a DateTextBox in a DataGrid and when I click on a cell that has a value of “”, NaN/NaN/NaN is displayed along with the Calendar – Any ideas?

  • Arnab Sengupta

    Hi,
    I have a question regarding Grid.cells.x (say DateTextBox) and Grid.editors.x (say DateTextBox). I am not sure which namespace (i.e. API to use in DataGrid)? Are we supposed to use only grid.cells.DateTextBox and not the editors.x API as in API docs? Can you please tell me which API of (DateTextBox and others) have been deprecated and will not be supported further. Also is the below syntax valid as its not working for “DataGrid”. I am using declarative DataGrid creation/declaration.

    Age

    Thanks and have a great day

    Arnab Sengupta.

  • John Kelly

    Hi,

    Sorry to bother you, but i’m stuck with a problem on dojox.data.JsonRestStore which i’m sure had a simple resolution that i’m just missing

    if i try to find an items children i use

    var values = nodestore1.getValues(item, “children”);

    but i get back an array of reference objects like… {“$ref” : “cid:/jrstest/JsonRestStore/Place/Child N64078” }

    I want to synchronously get the store item whose name is “Child N64078”, but despite my efforts using the dojox.json.ref apis I can’t seem to do it

    Any ideas ? Isn’t the JsonRestStore supposed to automatically resolve these ?

  • Pingback: Experiments with Dojo 1.5 Deferreds and Json Referencing — Gary Bishop()

  • Pingback: Dive into Dojo Data | SitePen Blog()

  • Martin

    This is only my first look, but I’m surprised by the fact that this thing seems to only handle simple REST objects and no-one else has complained.

    What about the situation –

    GET /container/{id}/widget/{id}/someproperty

    ?

  • Martin

    Or –

    GET /widget/{id}/propertythatisobject/propertysproperty

    ?

  • @Martin: In JsonRestStore, identity is correlated to the URI (that is what the I in URI stands for), or the trailing path in it. In your example, you can easily provide some-id/widget/some-id/someproperty as the identity of an item.

  • Darrell Bulloch

    How can I change the default Content-Range from items=0-24 to some larger value, say items=0-1000?

    I believe that would provide better performance by querying the server less often.

  • Darrell Bulloch

    How can I change the default Range from items=0-24 to some larger value, say items=0-1000?

    I believe that would provide better performance by querying the server less often.

  • Darrell Bulloch

    I tried the following:

    POISR_MAIN.store = new dojox.data.JsonQueryRestStore({
    target: “xhreq?action=getPoisr&timestamp=” + new Date().getTime() + “&sort=” + dojo.toJson(POISR_GLOBAL.sort) + “&criteria=” + encodedCriteria + “&count=”,
    idAttribute: “poisrId”,
    fetch: function(request) {
    request[“count”] = 1000;
    this.inherited(“fetch”, arguments);
    }
    });

    This worked for the 1st request sent to the server: Range items=0-999

    But, the 2nd request sent to the server was: Range items=25-1024
    which still used the 25 offset.

    I expected the 2nd request to be: Range items=1000-1999

  • @Darrell: The store doesn’t define the count, that is defined in the fetch request. In your case, I presume the fetch request is coming from the DataGrid (it has a default count of 25). If you want to change that, change the rowsPerPage property on the DataGrid to a higher number.

  • Darrell Bulloch

    Thanks very much Kris.

    That worked. But…

    Now the app is constantly getting a “Warning; Unresponsive script” message:

    “A script on this page may be busy, or it may have stopped responding. You can stop the script now, open the script in the debugger, or let the script continue.

    Script: http://localhost:8080/dojotoolkit/1.5.0/dojo.dojo.js:27

    I have the option to Continue, Debug script, or Stop script.

  • @Darrell: If you could choose to debug the script and let us know what the stack trace is and we can try to help. Note that this error message can indicate a problem anywhere in your application, and may not be specific to the JsonRestStore or the grid, it is very ambiguous.

  • Darrell Bulloch

    @Kris: I am unable to capture a stack track. Clicking the “Debug Script” option just results in the continual display of the same options, Continue, Debug script, or Stop script.

    Is there anything I need to do or install in order to generate the stack trace?

  • @Darrell: You can click on the pause button in the debugger to stop it while it is churning and see what it is working on.

  • Darrell Bulloch

    @Kris: I believe the stack trace below is what’s occurring when it “churns”

    (?)()43 (line 14)
    _3ad = [div.dojoxGridRowbar, div.dojoxGridRow, div.dojoxGridRow]
    (?)()43 (line 14)
    _3af = 196
    (?)()43 (line 14)
    _3bd = 196
    _3be = false
    (?)()43 (line 14)
    _483 = 0
    _484 = 1000
    (?)()43 (line 14)
    _4c7 = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    req = Object { start=0, count=1000, isRender=true, more…}
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)
    (?)()103 (line 119)
    _1f = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)
    _ff = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    _105 = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)
    _ff = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    _105 = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)
    _ff = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    _105 = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)
    _ff = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    _105 = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)
    _ff = [Trial] dojo.Deferred {}
    toString()dojo.js (line 14)
    _105 = [Trial] dojo.Deferred {}
    toString()dojo.js (line 14)
    dfd = [Trial] dojo.Deferred {}
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)

  • Darrell Bulloch

    @Kris: The “churning” seems to occur after data has been received from the server via a xhr request, while Dojo is trying to process/render the data in the grid.

    The response from the server consists of 100 objects with about 80 columns in each object.

    The problem doesn’t account when the rowsPerPage is set to 25, instead of 1000.

    I hope that helps.

    If not, please advise regarding any other things I can do to better identify the problem.

  • Darrell Bulloch

    @Kris: Please let me know if this is what you are after:

    (?)()43 (line 14)
    _3ad = [div.dojoxGridRowbar, div.dojoxGridRow, div.dojoxGridRow]
    (?)()43 (line 14)
    _3af = 196
    (?)()43 (line 14)
    _3bd = 196
    _3be = false
    (?)()43 (line 14)
    _483 = 0
    _484 = 1000
    (?)()43 (line 14)
    _4c7 = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    req = Object { start=0, count=1000, isRender=true, more…}
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)
    (?)()103 (line 119)
    _1f = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)
    _ff = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    _105 = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)
    _ff = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    _105 = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)
    _ff = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    _105 = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)
    _ff = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    _105 = [Object { aircraftFromRange=”04003″, aircraftThruRange=”04003″, amendDate=”2004-04-22 00:00:00.0″, more…}, Object { amendDate=”2004-04-14 00:00:00.0″, amendNumber=0, buyerCode=”25″, more…}, Object { amendDate=”2010-10-27 00:00:00.0″, amendNumber=2, buyerCode=”94″, more…}, 997 more…]
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)
    _ff = [Trial] dojo.Deferred {}
    toString()dojo.js (line 14)
    _105 = [Trial] dojo.Deferred {}
    toString()dojo.js (line 14)
    dfd = [Trial] dojo.Deferred {}
    toString()dojo.js (line 14)
    toString()dojo.js (line 14)

  • Brett

    Although I like the potential use of the Range and Content-Range headers, the spec does not appear to allow custom values inside of it (though it does allow custom values for Accept-Ranges).

  • Pingback: REST tips | Blog | SitePen()