RESTful JSON + Dojo Data

June 13th, 2008 - by Kris Zyp

jsonreststore-simple.png
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.

Bookmark and Share

Tags: , , ,

86 Responses to “RESTful JSON + Dojo Data”

  1. philou says:

    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> <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.

  2. Kris Zyp says:

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

  3. philou says:

    @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.

  4. [...] Dojo<->JSON Rest Store<->JSON<->JAX-RS<->JPA-EJB3 [...]

  5. miso says:

    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.

  6. Kris Zyp says:

    @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.

  7. [...] JsonRestStore is a Dojo Data store that provides a JSON-based RESTful interface to servers and implements the [...]

  8. RoryD says:

    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?

  9. Kris Zyp says:

    @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.

  10. Jesus Diaz says:

    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

  11. Kris Zyp says:

    @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.

  12. taras says:

    @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..

  13. mike says:

    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?

  14. chris says:

    @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…

  15. chris says:

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

  16. Nancy says:

    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?

  17. Kris Zyp says:

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

  18. Roland says:

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

  19. Roland Barcia says:

    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?

  20. J-R says:

    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"
    }]}]

  21. Kris Zyp says:

    @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

  22. Kris Zyp says:

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

  23. Freitags says:

    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?

  24. Darrell says:

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

  25. Darrell says:

    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.

  26. Kris Zyp says:

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

  27. Darrell says:

    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?

  28. Darrell says:

    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.

  29. Darrell says:

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

  30. Darrell says:

    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.

  31. Darrell says:

    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?

  32. Darrell says:

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

    Any ideas?

  33. Darrell says:

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

  34. Darrell says:

    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?

  35. Darrell says:

    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?

  36. Arnab Sengupta says:

    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.

Leave a Reply