The Grid/DojoData pair do not handle sparse data properly. Say you design a view defining columns for 10 fields. Now give the Grid a DojoData whose ItemFileReadStore(say) delivers sparse data: on each row, only some fields are populated. Some rows have 2 elements, some 10, some 7.
Unfortunately there's no way to tell the DojoData class the fields you defined in your view. DojoData uses the fields it finds in the first row to build a map of fields.
The result is that if the first row of the data does not have all fields populated, all rows in the Grid will display "?" in the cells corresponding to the first row's missing columns;
view = {cells: [{name:'A', field: 'a'}, {name:'B', field: 'b'}, {name:'C', field:'c'}]
data = {items: [{a: 1, b: 1}, {a: 2, b: 4, c: 4}, {a: 3, b: 7, c: 5}]
Grid will look like
A B C
-----------
1 1 ?
2 4 ?
3 7 ?My workaround was to override DojoData. I added a property 'view', which is a single view object as above. I override _setupFields to use that view if present. This technique is good enough for my purposes and works well. I don't know all the implications of what I've done, though, for other use cases -- I'm unsure whether my changes will break other cases. For example, _setupFields makes a mapping of fiueld names to/from integer indexes, and since in the sparse data case those indexes change from row to row, and I don't know how other parts of the Grid use that mapping, there's a potential dange there.
anyway, I hope dojo developers can incorporate support for sparse data into Grid, and here's my override:
dojo.provide("my.Model");
dojo.require('dojox.grid._data.model');
dojo.declare("my.Model", dojox.grid.data.DojoData, {
view: null,
_setupFields: function(dataItem){
// abort if we already have setup fields
if(this.fields._nameMaps){
return;
}
// set up field/index mappings
var m = {};
console.debug("setting up fields, view is ", this.view);
var source = (this.view)? dojo.map(this.view.cells[0], function(col){return col.field;}) :this.store.getAttributes(dataItem);
var fields = dojo.map(source,
function(item, idx){
console.debug('Model: map first data row attribute ', item, idx);
m[item] = idx;
m[idx+".idx"] = item;
// name == display name, key = property name
return { name: item, key: item };
},
this
);
this.fields._nameMaps = m;
console.debug("new fields:", fields);
this.fields.set(fields);
this.notify("FieldsChange");
},
});Here's how to use it:
var layout = [view0];
var myModel = new my.Model(null,store,{rowsPerPage: 20, query: someQuery, view: view0});
var grid = new dojox.Grid({model: myModel, structure: layout }, containerDiv);