PDA

View Full Version : Can a rendered grid receive a new data model?



christocracy
14 Oct 2006, 9:41 AM
I was looking through the ext.Grid docs for a function like


YAHOO.ext.grid.Grid::setDataModel(dm)


but there is none.

I wonder how does one re-use an instantiated Grid and supply it with new data?

looking at docs for YAHOO.ext.grid.DefaultDataModel, I see:


class YAHOO.ext.grid.DefaultDataModel
extends YAHOO.ext.grid.AbstractDataModel

This is the default implementation of a DataModel used by the Grid. It works with multi-dimensional array based data. Using the event system in the base class YAHOO.ext.grid.AbstractDataModel, all updates to this DataModel are automatically reflected in the user interface.
Usage:


I see functions getRows(), removeRow() and addRow(). will I use these to update the datamodel?

jack.slocum
14 Oct 2006, 9:45 AM
There are all kinds of methods on the models to manipulate the data. You can even reload the models data from scratch and the grid will automatically reflect the changes in the UI.

christocracy
14 Oct 2006, 10:01 AM
I see. I have my serverside framework already sending json responses, so I suppose I could use


YAHOO.ext.grid.JSONDataModel::loadData

void loadData(<Object> data, <Function> callback, keepExisting)

Overrides loadData in LoadableDataModel to process JSON data

Parameters:
data - The JSON object to load
callback -


I have an issue, where my framework's ajax implementation is Prototype-based, so I can't yet use the YAHOO ajax framework. does it make sense for me to use JSONDataModel?

jack.slocum
14 Oct 2006, 10:02 AM
There are more methods as well, like addRows(), removeAll(), filter(), insertRows() however they are marked private. They used to be public but they aren't overridden in subclasses (like XMLDataModel) and aren't supported on those models, so they were marked private to prevent issues with people using subclasses. If you are using a DefaultDataModel, then you can uses them just fine.

jack.slocum
14 Oct 2006, 10:04 AM
If you are using JSON, then yes you can use loadData to load a whole new structure. You can also use load() to load new data from the server. addRow, removeRow etc will add the rows to the data model's records, but not to your JSON object (it doesn't auto sync like the XMLDataModel).

christocracy
14 Oct 2006, 10:22 AM
what can you say to a guy who's tied to a prototype-based ajax implementation?

does it still make sense to use JSONDataModel?

jack.slocum
14 Oct 2006, 10:34 AM
It depends on what you are looking to do. Personally, I prefer JSON for readonly data because it's so lightweight. However XML is generally easier to use and most of my examples are XML because everyone can use XML and just about everything supports XML.

If you are looking to do 2 way read/write with data, the XMLDataModel has more features to facilitate updates to the server.

christocracy
14 Oct 2006, 10:44 AM
I'm all about JSON. all my ajax responses are JSON. no XML for me, man. tried it. JSON is quicker.

I mean, I can't yet take full advantage of LoadableDataModel's callback features.

I'll be handing JSONDataModel a data object that was returned through prototype's ajax.js.

jack.slocum
14 Oct 2006, 10:54 AM
Why would you do that when it's a 1 liner in JSONDataModel?



dataModel.load('foo.php');

dataModel.load('foo.php?bar=1&wtf=2'); // get

dataModel.load('foo.php', 'bar=1&wtf=2'); //post

dataModel.load('foo.php', {bar: 1, wtf: 2}); //auto encode

// callback
function wtf(){

}
dataModel.load('foo.php', {bar: 1, wtf: 2}, wtf);

dataModel.addListener('load', wtf);

dataModel.addListener('loadexception', wtf);


What other loading functionality you need?

christocracy
14 Oct 2006, 11:26 AM
A YAHOO ajax implementation for my framework is certainly possible, but it's a can of worms I can't yet get into.

I use a .NET-like php framework called prado.

I'll do some experiments. might be trivial.
gotta' get rid of prototype.
gotta' find all those Event.observe(), and $A(list).each(function(row) { ... } calls.

christocracy
14 Oct 2006, 11:57 AM
My server is answering the bell, just gotta send along my post params.

dumb question. given following fields:



[input type="hidden" name="PRADO_VIEWSTATE" value="197" /]
[input type="hidden" name="PRADO_POSTVALIDATION" value="aabe38ae68a4532a44de0f5bcaf9c8c9@1160852203" /]


in prototype, I'd get the values via:


var viewstate = $F('PRADO_VIEWSTATE');
var postvdr = $F('PRADO_POSTVALIDATION');


once I send those params along, I might almost get kosher ajax responses.

jack.slocum
14 Oct 2006, 12:06 PM
Generally I just add an id to them and access them like everything else.

christocracy
14 Oct 2006, 12:09 PM
yup, just hacked the framework to do just that. they did that to every other field...don't know why they missed those two.

christocracy
14 Oct 2006, 6:07 PM
so I've settled on using DefaultDataModel, using the private functions as you suggested (removeAll(), addRows() ). that'll do fine for me.

now, I wonder how I might inform DefaultDataModel of which index in incoming data will represent the "id" field, and should not be rendered as column data, but which will be available to me when requested (when a dragdrop occurs and I'm building an ajax request)

in my case, I'm sending back an un-hashed array where the id field is guaranteed to be the last column.

I think I'll be over-riding DefaultDataModel.

I think I need to send my extension a schema object, as in JSONDataModel.

jack.slocum
14 Oct 2006, 11:30 PM
That is definitely the most flexible route.

Another solution that is probably easier to implement, is to use the dataIndex property on the columns to map columns to arbitrary data column indexes. Then override getRowId():

yourDataModel.getRowId = function(rowIndex){
var row = this.data[rowIndex];
return row[row.length-1];
};

christocracy
15 Oct 2006, 9:39 AM
initially I extended DefaultDataModel, but I changed my mind and extended from LoadableDataModel, after all. Loadable has paging/sorting stuff that I can take advantage of.

the thing with my serverside framework, is that I have it sending back an array of JSON responses, each targetted to a particular javascript UI control. sometimes I have several grids that need to be updated simultaneously and I don't want each one initiating unique callbacks.

but having it loadable will come in handy for implementing a "live grid"; paging, sorting.

given grids as shown, as in iTunes, clicking a Genre will requre 3 grids be updated (Artist, Album, Library)

[Genre][Artist][Album]
[ Library ]

so server will send something like:


[{sender:'Artist', data : []}, {sender:'Album', data : []}, {sender:'Library', data : []}]

jack.slocum
15 Oct 2006, 9:56 AM
Sounds like you need a controller to marshall requests. The controller requests the json data and sends individual pieces of the result object to the appropriate data model via loadData.

Or you could get tricky with it and add a short delay on marshalled requests (say 250 milliseconds) and automatically queue and send multiple requests at once. This way when the page loads, it might fire 5 requests and they would all be queued and sent as 1. Then you override data model to call your controller instead of asyncRequest, maybe UpdateManager as well. Minimal code change and great responsive app. I like it.

christocracy
15 Oct 2006, 11:27 AM
>Sounds like you need a controller to marshall requests.

yes I do. you got one?

jack.slocum
15 Oct 2006, 12:42 PM
It shouldn't be too hard to implement. Here's a little skeleton:



RequestQueue = function(){
this.task = new YAHOO.ext.util.DelayedTask(this.executeRequest, this);
this.queue = [];
this.delay = 250; // 250 millsecond delay
};
RequestQueue.prototype ={
queueRequest : function(...){ // your args (or same args as asyncRequest?)
// convert passed args into storable array, you could build an object
// here as well
this.queue.push(Array.prototype.concat.call(arguments));
this.task.delay(this.delay); // queues a timeout, if called again timeout starts over
},

executeRequest : function(){
// build your single request from queued requests
}
};


As you can see it's pretty easy. Then in your data model you can replace the call to Connect.asyncRequest with a call to your RequestQueue. If you are really brave you could replace YAHOO.util.Connect.asyncRequest with your request queue:


RequestQueue.asyncRequest =
YAHOO.util.Connect.asyncRequest.createDelegate(YAHOO.util.Connect);
YAHOO.util.Connect.asyncRequest = RequestQueue.queueRequest.createDelegate(RequestQueue);


Then in RequestQueue.executeRequest instead of calling YAHOO.util.Connect.asyncRequest, you would call this.asyncRequest.

christocracy
15 Oct 2006, 12:54 PM
>If you are really brave you could replace YAHOO.util.Connect.asyncRequest
>with your request queue:

cheers! I'll do this.

christocracy
15 Oct 2006, 1:15 PM
Bravo, once again, Mr. Jack.
(oops, wrong topic :)

christocracy
18 Oct 2006, 12:48 PM
I just implemented you RequestQueue idea. took 5 minutes to plug it in.

it does make things snappier.

dig.

jack.slocum
18 Oct 2006, 4:30 PM
Care to send me a copy so I can check it out? jack.slocum AT yahoo DOT com if yes. :)