Search This Blog

Loading...

Thursday, February 25, 2010

jQuery's jqGrid - feeding JSON data from a Web Service

Intro:

In Looking for Perfect Web Toolkit story I mused about a need for a robust web stack that would satisfy a progger insane enough to contemplate a competitor to GitHub's of the world. The order is tall so the primary demand for that magical web stack is one - make the stack do the grunt work.

"Do the grunt work" in today's case means - MVC-like behavior of the JavaScript toolkit.

Idealistic view of such a stack:

1) Very light web-templating system / server serving the frames with JS hooks. (See ASP.Net Master Pages, or some Python-based templating system on top of Twisted as example (this is a hook for future post. Link to follow.).

2) Web Service feeding data and settings as JSON to JS widgets activated by JS hooks. (.Net WebService examples 1, 2, 3, and the most insightful. Python-based Twisted example is coming in a future post. Will add link here.)

3) We stay on the page as long as possible. JS bulds / removes DOM / Modal dialogs for us.

4) "State" is kept within JS client, not on the server. (some cashing of the state is there, but not mandatory, as JS-based auth detects when server thinks auth is out of sync and prompts reauth.)

Practical Example:
Need to present tabular data in a grid... Not any grid, but the one that allows insanely flexible and simple filtering, reordering and resizing of columns, and, hopefully, contextual element edit functionality - entirely in the browser, without postbacks to server to rerender the view / elements or dress the data in a table.

In the race to the top, jQuery's jqGrid won over ExtJs's grids. More on the competition here (link to be added).

Populating jqGrid:

Unlike ExtJs's grids, jqGrid does NOT work off a DataStore of any kind, "Everything" is geared towards the old days - pulling Gets or Posts off various (and I mean VARIOUS / separate) URLs.

This is bad. This fails the vision of a web stack outlined above, where "state" is shifted to JS client. I want to manage "log in" keys with the JS client and have it send the hash on every data request. Injecting authentication credentials becomes pain when your widgets just wants to know the post URL and assembles the AJAX request by itself.

By "everything" I mean:
- Default (non-filtered) data pull.
- Search (filtered) data pull. ()
- Edit (HTTP Post) with consecutive grid reload.

- Default data pull:
Luckily, default data pull allows one to specify either a method argument, or function to run to get the data. This means, if you really want to play with post arguments, you replace the AJAX call and trigger the grid population by hand. This is fine, since this allows me to populate the POST the way I want (the way .Net-based WebService can actually take it)

Example:

function processrequest(postdata) {
jQuery.ajax({
type: "POST",
url: "./dataserver",
data: JSON.stringify(postdata), // we can inject whatever data we want here.
contentType: "application/json; charset=utf-8",
dataType: "json",
// success: function(msg) {alert(msg);}
complete: function(data,stat){
if(stat=="success") {
var o;
o = jQuery("#list")[0]
// note, this example is from a NON-ASP.Net WebService.
// there your data is wrapped into dictionary with only one key - "d"
// You will have to undress data by JSON.parse(data.responseText)['d']
o.addJSONData(JSON.parse(data.responseText));
}
}
});
}

// Declare your jQuery jqGrid:
jQuery("#list").jqGrid({
// url: './dataserver', // you do NOT need this anymore! Yey!
datatype: processrequest, // pointer to you magic data-pulling function
...
})
Example of what server gets:
Content-Type application/json; charset=utf-8
X-Requested-With XMLHttpRequest
Referer http://127.0.0.1/index.html
Content-Length 115

Content: {"_search":false,"nd":1267138960090,"rows":20,"page":1,"sidx":"invid","sord":"desc"}
Good. Getting plain data from a WebService. So, how can we search?

"Toolbar" search is sexy but, breaks horribly when combined with sortable columns, and does not allow you to override the AJAX call. It literally fails when "url" key is not set on the grid.

Advanced and simple search work in very similar ways. A modal dialog pops up. It's built automatically, based on the flags in your flags in Column Model. No extra work required on the part of progger. These two searches use the datetype: value (our magic function) to communicate the searched fields to the server.

Simple search spreads the search args among other properties of the post. However, Advanced method packs all of "filter" args into single key - beauty and pleasure to work with. Moreover, Advanced search keeps track of already set up filters. You toggle the search dialog and all of your search fields are there.

Example of what gets sent:

(POST request headers)
...
Content-Type application/json; charset=utf-8
X-Requested-With XMLHttpRequest
Referer http://127.0.0.1/index.html
Content-Length 184

Content: {"_search":true,"nd":1267139196421,"rows":20,"page":1,"sidx":"invid","sord":"desc","filterV1":"{\"groupOp\":\"AND\",\"rules\":[{\"field\":\"amount\",\"op\":\"eq\",\"data\":\"100\"}]}"}

Good. We choose Advanced Search and 2 out of 3 items can be fed by the same WebService. What about built-in editing of the items? This is where we hit the brick wall. All that Editing code asks from us is "Gime the URL i would post whatever I decide." If you don't define editurl property on the grid, editing code complains.

Short for rewriting the code that in non-minified version sits in grid.formedit.js (see lines with $.ajax, there are 2 of them ) there is no easy, practical way make edit POST JSON in a WebService compatible way.

Conclusion:

It's possible, with very little effort to push JSON from a WebService into jQuery's jqGrid. Very easy. But, that applied only to environments where you don't need to edit the data you see in the grid - just pull and filter it.

Dontcha worry. I'll make it work for editing too.

1 comments:

Anonymous said...

I have seen many similar code of yours since I have been searching for days (8 hours/day), to find a complete working ASP.NET webform example (webservice.asmx or httphandler.ashx), but had no sucess. I saw a few MVC examples but I am not able to compile it since I do not know the framework.

In your code, what goes between the "..." after the keyword function in the jquery section that initializes the grid?

Do you have a complete working code (javascript and the webservice), that works for both sorting and filtering for a database or a random set of data?

Please drop me an email if you have a chance to respond to this message. My email address is sau_rau (at) yahoo.com. Thanks for your help.

Daryl