Login Register

Solved : dojo.rpc.JsonService + dojox.data.AndOrWriteStore + dojox.grid.DataGrid

Ok, so far I played with static data to display my grid which works great. Now I need to get my data from the server. I am using struts2 + jsonplugin and got my json-rpc working. I am using JsonService on my jsp to get the results as shown

<s:url id="sampleUrl" namespace="/json-rpc" action="SampleAction"/>
<script type="text/javascript">
    //load dojo RPC
    dojo.require("dojo.rpc.JsonService");
    
    //create service object(proxy) using SMD (generated by the json result)
    var service = new dojo.rpc.JsonService("${sampleUrl}");
    var defered = service.getGridData(); //my action method to get real data

    //now i see defered.results[0] has the information, do i need make a callback function
    //i don't know i am missing right here, not able to get my results out of the service method.
    //it returns null. 

    var dataStore = new dojox.data.AndOrWriteStore ({
        data: defered.results[0]
    });

</script>

any ideas how to get the results of the defered object above.

guys, I am putting together the whole grid example with struts2 + jsonplugin + dojogrid soon.

Just a thought: The defered

Just a thought: The defered probably hasn't gotten the results yet at the time the store is created. I'm guessing you need to set up the store in the defered.addCallback().

Thanks for the response. I

Thanks for the response. I tried

var service = new dojo.rpc.JsonService("${dataUrl}");
var defered = service.getSampleGrid();
			
var sampleData;
defered.addCallback(function (results) {
	sampleData = results;
	console.debug("identifier " + sampleData.identifier);
	console.debug("items[0].dow " + sampleData.items[0].dow);
});
		          	  
var dataStore = new dojox.data.AndOrWriteStore ({
       	data: sampleData
});

I can see the my json object build as I exprected. but the grid doen't render..... And I think its again the same issue dataStore hasn't gotten sampleData. Now when I move this store into the callback method..... now the grid has no store initialized. It looks like I need to move my my grid creation into the callback method.

Is this the only way............. any suggestions............

Set up the data store in the

Set up the data store in the callback function. Then -- also in the callback function -- call grid.setStore(store, query, queryOptions).

The grid doen't render

The grid doen't render .............. I see the store getting set correctly on the grid

var grid = new dojox.grid.DataGrid({
	id: "grid",
	structure: grid.grid_definitions.sample.structure
});
			
var service = new dojo.rpc.JsonService("${dataUrl}");

service.getSampleGrid().addCallback(function (results) { 
	var dataStore = new dojox.data.AndOrWriteStore ({
       		data: results
	});
			
	grid.setStore(dataStore, "{ namespace: '*' }", "{ignoreCase: true}");
	dojo.byId("magicGrid").appendChild(grid.domNode);
	grid.render();
});

and I have a div in my html with magicGrid as id

any ideas?

Your grid.setStore query and

Your grid.setStore query and options parameters should be objects, not strings. Don't surround them with quotes.

Also, if you do the appendChild for the grid before the setStore, you shouldn't need to call grid.render(). (The setStore calls render, so you're rendering the grid twice here.)

Seriously we need a store

Seriously we need a store which works with JsonService onfetch

Need a store..

Anyone have an implementation of this that works?

I came across this link and

I came across this link http://www.dojotoolkit.org/forum/dojox-dojox/dojox-grid-support/queryrea... and decided to extend AndOrWriteStore to override _fetchItems method as shown:

dojo.provide("custom.data.JsonRPCAndOrWriteStore");

dojo.require("dojox.data.AndOrWriteStore");
dojo.require("dojo.rpc.JsonService");

dojo.declare("custom.data.JsonRPCAndOrWriteStore", dojox.data.AndOrWriteStore, {
 	constructor: function(params){
    	this.service = new dojo.rpc.JsonService(params.url);
    	this.serviceMethod = params.serviceMethod;
    	this.serviceArgNames = [];
    	
    	// get argument names based on serviceMethod
    	var smdMethodArray = this.service.smd.methods;
    	for (var i in smdMethodArray) {
    		var smdMethod = smdMethodArray[i];
    		if (smdMethod.name == this.serviceMethod) {
    		    var paramArray = smdMethod.parameters;
    		    for (var j in paramArray) {
		    		this.serviceArgNames[j] = paramArray[j].name;	
		    	}
    			break;
    		}
    	}
	},
	
	// invokes service 
    invokeJSONService: function(params){
        // hold serviceMethod arguments in array
    	var serviceArgValues = [];
    	
    	// get serviceMethod arguments from serverQuery
    	for (var i in this.serviceArgNames) {
    		serviceArgValues[i] = params.serverQuery[this.serviceArgNames[i]];
    	}
		
		// call service method    	
		return this.service[this.serviceMethod].apply(this, serviceArgValues);
    },
	
	// overrides superclass method to call JsonService for fetching items
	_fetchItems: function(keywordArgs, findCallback, errorCallback){
		//	summary: 
		//		See dojo.data.util.simpleFetch.fetch()
		//		filter modified to permit complex queries where
		//			logical operators are case insensitive:  
		//			, NOT AND OR ( ) ! && ||
		//			Note:  "," included for quoted/string legacy queries. 
		var self = this;
		var filter = function(requestArgs, arrayOfItems){
			var items = [];
			if(requestArgs.query){
				var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false; 
				//for complex queries only:  pattern = query[:|=]"NOT id:23* AND (type:'test*' OR dept:'bob') && !filed:true"
				//logical operators are case insensitive:  , NOT AND OR ( ) ! && ||  // "," included for quoted/string legacy queries.
				var query = requestArgs.query;
				if(typeof query != "string"){
					query = dojo.toJson(query);	
					query = query.replace(/\\\\/g,"\\"); //counter toJson expansion of backslashes, e.g., foo\\*bar test.
				}
				query = query.replace(/\\"/g,"\"");   //ditto, for embedded \" in lieu of " availability.
				var complexQuery = dojo.trim(query.replace(/{|}/g,"")); //we can handle these, too.
				var pos2, i;
				if(complexQuery.match(/"? *complexQuery *"?:/)){ //case where widget required a json object, so use complexQuery:'the real query'
					complexQuery = dojo.trim(complexQuery.replace(/"?\s*complexQuery\s*"?:/,""));
					var quotes = ["'",'"'];
					var pos1,colon;
					var flag = false;
					for(i = 0; i 0 && !err){
							op = complexQuery.match(begRegExp);
							
							//get/process/append one or two leading logical operators.
							while(op && !err){ //look for leading logical operators.
								complexQuery = dojo.trim(complexQuery.replace(op[0],""));
								op = dojo.trim(op[0]).toUpperCase();
								//convert some logical operators to their javascript equivalents for later eval.
								op = op == "NOT" ? "!" : op == "AND" || op == "," ? "&&" : op == "OR" ? "||" : op; 
								op = " " + op + " ";
								sQuery += op;
								op = complexQuery.match(begRegExp);
							}//end op && !err
							
							//now get/process/append one key:value pair.
							if(complexQuery.length > 0){
								pos = complexQuery.indexOf(":");
								if(pos == -1){
									err = true;
									break;
								}else{
									key = dojo.trim(complexQuery.substring(0,pos).replace(/\"|\'/g,""));
									complexQuery = dojo.trim(complexQuery.substring(pos + 1));
									tok = complexQuery.match(/^\'|^\"/);	//quoted?
									if(tok){
										tok = tok[0];
										pos = complexQuery.indexOf(tok);
										pos2 = complexQuery.indexOf(tok,pos + 1);
										if(pos2 == -1){
											err = true;
											break;
										}	
										value = complexQuery.substring(pos + 1,pos2);
										if(pos2 == complexQuery.length - 1){ //quote is last character
											complexQuery = "";
										}else{
											complexQuery = dojo.trim(complexQuery.substring(pos2 + 1));
										}
										sQuery += self._containsValue(candidateItem, key, value, dojo.data.util.filter.patternToRegExp(value, ignoreCase));
									}
									else{ //not quoted, so a space, comma, or closing parens (or the end) will be the break.
										tok = complexQuery.match(/\s|\)|,/);
										if(tok){
											var pos3 = new Array(tok.length);
											for(var j = 0;j 1){
												for(var j=1;j 0)
						} //end while complexQuery.length > 0 && !err, so finished the i-th item.
						match = eval(sQuery);
					} //end else is non-null candidateItem.
					if(match){
						items.push(candidateItem);
					}
				} //end for/next of all items.
				if(err){  //soft fail.
					items = [];
					console.log("The store's _fetchItems failed, probably due to a syntax error in query.");
				}
				findCallback(items, requestArgs);
			}else{  // No query...
				// We want a copy to pass back in case the parent wishes to sort the array. 
				// We shouldn't allow resort of the internal list, so that multiple callers 
				// can get lists and sort without affecting each other.  We also need to
				// filter out any null values that have been left as a result of deleteItem()
				// calls in ItemFileWriteStore.
				for(var i = 0; i < arrayOfItems.length; ++i){
					var item = arrayOfItems[i];
					if(item !== null){
						items.push(item);
					}
				}
				findCallback(items, requestArgs);
			} //end if there is a query.
		}; //end filter function
			
		if(this._loadFinished){
			filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
		}else{  
			if(this.serviceMethod) {
				var serviceHandler = this.invokeJSONService(keywordArgs);
				
				serviceHandler.addCallback(dojo.hitch(this, function(result){
					try{
						this._loadFinished = true;
						this._getItemsFromLoadedData(result[0]);
						this._jsonData = null;
						filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
					}catch(e){
						errorCallback(e, keywordArgs);
					}
					
				}));
			
				serviceHandler.addErrback(function(error){
					errorCallback(error, request);
				});
			}
			else if(this._jsonFileUrl){
				//If fetches come in before the loading has finished, but while
				//a load is in progress, we have to defer the fetching to be 
				//invoked in the callback.
				if(this._loadInProgress){
					this._queuedFetches.push({args: keywordArgs, filter: filter});
				}else{
					this._loadInProgress = true;
					var getArgs = {
							url: self._jsonFileUrl, 
							handleAs: "json-comment-optional",
							preventCache: this.urlPreventCache
						};
					var getHandler = dojo.xhrGet(getArgs);
					getHandler.addCallback(function(data){
						try{
							self._getItemsFromLoadedData(data);
							self._loadFinished = true;
							self._loadInProgress = false;
							
							filter(keywordArgs, self._getItemsArray(keywordArgs.queryOptions));
							self._handleQueuedFetches();
						}catch(e){
							self._loadFinished = true;
							self._loadInProgress = false;
							errorCallback(e, keywordArgs);
						}
					});
					getHandler.addErrback(function(error){
						self._loadInProgress = false;
						errorCallback(error, keywordArgs);
					});
				}
			}else if(this._jsonData){
				try{
					this._loadFinished = true;
					this._getItemsFromLoadedData(this._jsonData);
					this._jsonData = null;
					filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
				}catch(e){
					errorCallback(e, keywordArgs);
				}
			}else{
				errorCallback(new Error("dojox.data.AndOrReadStore: No JSON source data was provided as either URL or a nested Javascript object."), keywordArgs);
			}
		} //end deferred fetching.
	}
});

and this is magic code segment in _fetchItems() method to make json-rpc work with store.

if(this.serviceMethod) {
				var serviceHandler = this.invokeJSONService(keywordArgs);
				
				serviceHandler.addCallback(dojo.hitch(this, function(result){
					try{
						this._loadFinished = true;
						this._getItemsFromLoadedData(result);
						this._jsonData = null;
						filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
					}catch(e){
						errorCallback(e, keywordArgs);
					}
					
				}));
			
				serviceHandler.addErrback(function(error){
					errorCallback(error, request);
				});
			}

I kept a break point and I can see my result (with items) everything available.

In my jsp I provide

var dataStore = new custom.data.JsonRPCAndOrWriteStore ({
             	url: "${dataUrl}",
             	serviceMethod: "getSampleGrid"
});

No errors.............. but grid has no data..................

Stuck and need help......

sweet the above piece

sweet the above piece actually works..................

This code doesn't work, it

This code doesn't work, it gives me lots of parse error. Can you post it again?

I've been able to do a read-only store by overloading the _processItems, fetch and _doQuery methods from the ServiceStore. The idea is comes from http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/grid/tests/yaho...

dojo.declare("TestStore", dojox.data.ServiceStore, {
_processResults: function(results, def){
//alert(results.result.pagination);
var totalCount = 0;

if(results && results.pagination){ // Tweek your code here to read the response correctly from your rpc service.
totalCount = results.pagination.num_results;
results = results.data;

}
var resultSet = this.inherited(arguments);
resultSet.totalCount = totalCount > 1000 ? 1000 : totalCount;
return resultSet;
},
fetch: function(request){

if(request.query){
if(request.count){
request.query['results'] = request.count;
}
if(typeof request.start != "undefined"){
request.query['start'] = request.start + 1;
}
}
return this.inherited(arguments);
},
_doQuery: function(args){
// This here needs to be modified to match the json-rpc service arguments and the `args`.
// For my test I hardcoded the 2 required parameter for the service but ideally the matching would be automatic using somekind
// of mapping.

return this.service.apply(this.service, [(args.start / args.count)+1,args.count]);
}

});

In your HTML, you can invoke it like this using dojox.rpc.Service:

var service = new dojox.rpc.Service('/path/to/service/smd/or/something');
var store=new testStore({service:service.someMethods});

In my test I pass the store to a grid and the auto paging works.

The problem I'm facing for the Write API is to map the json-rpc service methods properly to the API. I want to do this so I don't have to overload a store for each of my services.

Hope this help.

I am on nightly build and

I am on nightly build and the above code works for me..........

Parse errors

Just like Beau, i get some parse errors with this.

Are those loops correct?:
for(i = 0; i 0 && !err){
//*snip*

var pos3 = new Array(tok.length);
for(var j = 0;j 1){
for(var j=1;j 0)
} //end while complexQuery.length > 0 && !err, so finished the i-th item.
Any help would be appreciated.
-Lo