What I needed was a column model dynamically adjusting depending on the data received from data store (i.e. JSON provided by server). Something like the following:
Where each site has a different set of dimensions (rows) and different set of auditors (columns).
It turned out that the problem was actually two-fold - first dynamically change the columns and then display the editable checkboxes instead of true/false values.
To change the columns I used metaData attribute in my JSON. Including metaData attribute causes Ext.data.JsonReader to be adjusted to the new set of fields and other config parameters and fire metachange event. Here's an example of the JSON with metaData:
{
"results": 3,
"auditors": [
{"dimension_name": "Audits and Reviews", "auditor_3": false, "dimension_id"
: 10, "id": 10, "auditor_4": false, "auditor_18": false},
{"dimension_name": "Emergency Management & Fire Safety", "auditor_3": false, "dimension_id": 8, "id": 8, "auditor_4": false, "auditor_18": false}
.
.
.
],
"metaData": {
"fields": [
{"name": "id"},
{"type": "string", "mapping": "dimension_name", "name": "auditor[dimension]"},
{"type": "int", "mapping": "dimension_id", "name": "auditor[dimension_id]"},
{"type": "bool", "name": "auditor_3", "header": "Dasha Alexo"},
{"type": "bool", "name": "auditor_18", "header": "Tester 3"},
{"type": "bool", "name": "auditor_4", "header": "Zobak Zobakovic"}],
"root": "auditors",
"totalProperty": "results",
"id": "id"
}
}
In this case it's the number of auditors (and their names) that's changing. My data types are booleans but displaying any other data type would look pretty much the same.
Next I needed to update the column model based on the new meta data. I did that by adding metachange listener to my store
auditors_store.addListener("metachange", function(store, meta){
var grid = Ext.getCmp('auditors-grid');
var columns = [
{header: 'Dimension', dataIndex: 'auditor[dimension_id]', hidden: true},
{header: 'Dimension', dataIndex: 'auditor[dimension]', width: 200}
];
for (var i = 3; i < meta.fields.length; i++ ) {
var plugin = new Ext.grid.CheckColumn({
header: meta.fields[i].header,
dataIndex: meta.fields[i].name,
grid: grid,
width: 120
});
columns.push(plugin);
plugin.init(grid);
//use columns.push( { header: meta.fields[i].header, dataIndex: meta.fields[i].name, type: meta.fields[i].type }); for fields that don't require plugins
}
grid.reconfigure(auditors_store, new Ext.grid.ColumnModel(columns));
});
I had to create and initialize the plugin for each new column as I needed editable checkboxes. For normal fields just use the usual column config object { header: meta.fields[i].header, dataIndex: meta.fields[i].name, type: meta.fields[i].type }.
The actual magic happens is in the last line. Grid has an obscure method reconfigure( Ext.data.Store store, Ext.grid.ColumnModel colModel ) that allows to switch the store and column model (the columns displayed) on the fly.
My next problem was to make the checkboxes editable. To do that I had to put a small fix to the CheckColumn plugin (see the plugin) as the original plugin assumes that the grid is not rendered when initializing, however, when dynamically adding columns the grid is already rendered so I had to change the following:
init : function(grid){
this.grid = grid;
this.grid.on('render', function(){
var view = this.grid.getView();
view.mainBody.on('mousedown', this.onMouseDown, this);
}, this);
},
to the following:
init : function(grid){
this.grid = grid;
if (this.grid.rendered) {
var view = this.grid.getView();
view.mainBody.on('mousedown', this.onMouseDown, this);
} else {
this.grid.on('render', function(){
var view = this.grid.getView();
view.mainBody.on('mousedown', this.onMouseDown, this);
}, this);
}
},
And that's all - nice and simple. If only there were more books on Ext :-(
12 comments: