PDA

View Full Version : Yet another Meta grid plugin ;)



Ronaldo
3 Feb 2009, 2:15 PM
Hi all,

I see more and more server side grid configuration solutions, so I thought I might post mine as well here. It's just a grid plugin and it's easily configurable.
The reason I wrote it is that it does not require much code in the grid itself, and that makes it very reusable.

Here's how I define my grid:



MyGrid = Ext.extend(Ext.grid.GridPanel, {
url: '/someUrl',
title: 'MyGrid',
remoteSort: true,
primaryEntity: 'Customer',
initComponent: function(){
var g=Ext.ux.grid;
this.plugins = [
new Ext.ux.grid.MetaGridPlugin(),
...
];
this.store = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: this.url
}),
reader: new Ext.data.JsonReader({
root: 'rows',
totalProperty: 'rowCount',
id: 'id',
fields: this.mapping
}),
baseParams: ...,
remoteSort: true
});
this.cm = new Ext.grid.ColumnModel([{ id: '', dataIndex: '', width: 100}]);
this.mapping = [{name: '', mapping: '', type: 'string'}];
MyGrid.superclass.initComponent.call(this);
},
....
});
Note that I do need a column model and a mapping, but that's just because the grid needs a column. But that setting will be overridden by the server's response.

The plugin adds a parameter 'meta' to the request, and the first time this parameter looks like
{"primary":"Customer","fields":[""],"requestMeta":true}Yes, it's JSON. I thought that a single field might reduce the changes of interfering with other parameters. It basically tells the server that the primary file/entity of the grid is the Customer file, it doesn't know about any fields, and that it needs the metadata to configure itself.

The response should be


{"success":true,
"rowCount":140,
"rows":[
{"id":"1052","name":"A customer name","address":"some address"},
... more data ...
],
"metaData": {
"fields":[{"name":"id"},{"name":"name"},{"name":"address"}],
"root":"rows",
"totalProperty":"rowCount",
"id":"id",
"successProperty":"success"
}
}

In further requests, the grid has configured itself, and requests the fields to be displayed; the meta parameter now contains:


{"primary":"Customer","fields":["id","name","address"]}

And you don't need include the metaData in your response.
Of course, this makes the server side a little more complex, as it needs to know about a 'customer' and the fields available. Moreover, it should be able to create a query based on the fields in the request.

Btw, using php, doctrine and zend, I have all the metadata (fields, fieldtypes etc) in my doctrine model.

And here's the plugin.



/**
* @Author Twensoc - Ronald van Raaphorst
* @Version 0.9
* @License GPL v3
*/
Ext.ux.grid.MetaGridPlugin = function(config) {
Ext.apply(this, config, {
requestMeta: true
});
}

Ext.ux.grid.MetaGridPlugin.prototype = {
init : function(grid) {
this.grid = grid;
grid.store.on('metachange', this.onMetaChange, this);
grid.store.on('beforeload', this.onBeforeLoad, this);
grid.on('beforeviewchange', this.onBeforeViewChange, this);
grid.on('viewchange', this.onViewChange, this);
},
destroy: function() {
delete(this.grid);
},
onBeforeLoad: function(store, options) {
var flds = [];
store.fields.each(function(item) {
flds.push(item.name);
}, this);
p = {
primary: this.grid.primaryEntity,
fields: flds
}
if(this.requestMeta) {
p.requestMeta = this.requestMeta;
}
store.baseParams.meta = Ext.util.JSON.encode(p);
},
onMetaChange : function(store, meta) {

var colModel = this.createColumnModel(meta.fields);
if(meta.sortInfo) {
//this.grid.store.sortInfo = meta.sortInfo;
}
this.requestMeta = false;
this.grid.reconfigure(store, colModel);
},
onBeforeViewChange: function(grid, view, custom) {
this.requestMeta = true;
},
onViewChange: function(grid, view, custom, fields) {
if(custom==true && fields) {
this.grid.store.removeAll();
var colModel = this.createColumnModel(fields);
this.grid.reconfigure(this.grid.store, colModel);
}
},
createColumnModel: function(flds) {
var columns = [];
var autoExpand = false;
var fld = null;

for(var i=0,n=flds.length; i<n; i++) {
fld = flds[i];
if(fld.hidden == true)
continue;
fld = this.createColumn(fld);
fld.id = fld.id || 'col'+i;
columns.push(fld);
}
return new Ext.grid.ColumnModel(columns);
},
createColumn: function(fld) {
fld.header = fld.header || fld.name;
fld.dataIndex = fld.mapping || fld.name;
fld.width = fld.width ? (typeof field.width == 'string' ? parseInt(field.width) : fld.width) : 100;
delete fld.name;
return fld;
}
}Note that it's version 0.9, as some column properties are not supported yet. I'm working on it ;)

I already have taken this idea a step further, and having given each grid their own id, I can compose different views for the same grid, as you can see in the attachments.
Picture 2 shows a list of views defined for a log grid. Picture 1 shows the views, all the fields available (including parent tables), and the fields set for the plain view.
You can drag and drop fields from the tree to the field list and save them as a view. Later on, I intend to add filters to a view, so everyone can easily adapt every grid to their own preferences and switch between different views of the same data.

Now I intend to publish this tool too, but if it's used commercially, I'll ask a small fee. Drop me a note if you're interested.

joseadriano
5 Mar 2009, 3:18 PM
Do you have an online demo??

I tried to use, but , it doesn´t load ...

Could you please post a complete example ou an online demo?

mjlecomte
5 Mar 2009, 3:29 PM
You should be able to work this plugin with this code (quite similar but implented as an extension as posted):
http://extjs.com/forum/showthread.php?p=275575#post275575

tonedeaf
8 Mar 2009, 1:21 AM
Note that I do need a column model and a mapping, but that's just because the grid needs a column. But that setting will be overridden by the server's response.


How do you specify the column model in the MetaData returned by server?
Your example only lists the field names included in MetaData, not the column model.

Field names will be used by the store to insert the data in the rows. While the column model will define the columns in the grid like:


{
header: 'Customer',
width: 200,
groupable: false,
dataIndex: 'Customer.name'
}


Can you include a complete json server response including the column model?

EDIT: Got it working, the colModel properties are part of the fields array as shown in this post by mjlecomte:
http://extjs.com/forum/showthread.php?p=275578#post275578

tonedeaf
8 Mar 2009, 4:14 AM
Some changes: createColumn() function


createColumn: function(fld) {
fld.header = fld.header || fld.name;
fld.dataIndex = fld.mapping || fld.name;
fld.width = fld.width ? (typeof field.width == 'string' ? parseInt(field.width) : fld.width) : 100;
delete fld.name;
return fld;
}


should be:



createColumn: function(fld) {
fld.header = fld.header || fld.name;
fld.dataIndex = fld.dataIndex == undefined ? fld.mapping || fld.name : fld.dataIndex;
fld.width = fld.width ? (typeof field.width == 'string' ? parseInt(field.width) : fld.width) : 100;
delete fld.name;
return fld;
}


The server side colModel json can define an independent dataIndex. Your code overwrites it with the store fields mapping or name

EDIT: Also convert the global variable p to a local variable on line 28


var p = {
primary: this.grid.primaryEntity,
fields: flds
}

jay@moduscreate.com
9 Mar 2009, 6:37 AM
i would like to suggest that you reduce up the number of borders placed to make the UI cleaner :)

tonedeaf
10 Mar 2009, 10:47 AM
have you got it working with a PagingToolbar? The grid doesn't display any data apart from the first page.

galdaka
10 Mar 2009, 1:50 PM
Live demo please ;)

Thanks in advance,

mjlecomte
10 Mar 2009, 5:55 PM
have you got it working with a PagingToolbar? The grid doesn't display any data apart from the first page.

Huh? Sorry, I just don't even know what else to say.

mjlecomte
10 Mar 2009, 5:57 PM
Live demo please ;)

Thanks in advance,

There's a link above to similar package with all info needed to create working version. Granted I realize that I think more than half of your posts are for people to post a working demo.

tonedeaf
11 Mar 2009, 2:58 AM
Huh? Sorry, I just don't even know what else to say.

I'll rephrase my question.

When trying to use this plugin with a PagingToolbar, I can only display the first page. Clicking next to go to 2nd or subsequent pages, doesn't load the data in the grid. Although looking at the POST reponse returned by server, I can see that the correct is data coming, but not getting loaded.

So, are there any compatibility issues with the PagingToolbar for this plugin?

mjlecomte
11 Mar 2009, 6:47 AM
I'd think someone might be able to help you if you posted the response for first and next page loads. A grid with a couple of fields would be sufficient for a proof of concept here.