I am using a JsonReader to map Json data to variables to be used in a grid/form. The back end is in Java and there are complex objects which I Jsonify and pass to the ExtJS front end. This is a part of my JsonReader which tries to retrieve a nested object -
{name:'status', type: 'string', mapping: 'status.name'}
This works fine when status has a value (no开发者_如何学JAVAt null in the server), but the grid load fails when status is null. Currently the work around I have is to send an empty object from the server in case of null, but I assume there should be a way to handle this in ExtJS. Please suggest a better solution on the ExtJS side.
I can think of two possibilities - one documented and one undocumented:
use the
convert()
-mechanism ofExt.data.Field
:{ name:'status', mapping: 'status', convert: function(status, data) { if (!Ext.isEmpty(status) && status.name) { return status.name; } else { return null; } } }
The
mapping
property can also take an extractor function (this is undocumented so perhaps it may be a little bit risky to rely on this):{ name:'status', mapping: function(data) { if (data.status && data.status.name) { return data.status.name; } else { return null; } } }
Use this safe json reader instead:
Ext.define('Ext.data.reader.SafeJson', {
extend: 'Ext.data.reader.Json',
alias : 'reader.safe',
/**
* @private
* Returns an accessor function for the given property string. Gives support for properties such as the following:
* 'someProperty'
* 'some.property'
* 'some["property"]'
* This is used by buildExtractors to create optimized extractor functions when casting raw data into model instances.
*/
createAccessor: function() {
var re = /[\[\.]/;
return function(expr) {
if (Ext.isEmpty(expr)) {
return Ext.emptyFn;
}
if (Ext.isFunction(expr)) {
return expr;
}
if (this.useSimpleAccessors !== true) {
var i = String(expr).search(re);
if (i >= 0) {
if (i > 0) { // Check all property chain for existence. Return null if any level does not exist.
var a = [];
var l = expr.split('.');
var r = '';
for (var w in l) {
r = r + '.' + l[w];
a.push('obj' + r);
}
var v = "(" + a.join(" && ") + ") ? obj." + expr + " : null";
return Ext.functionFactory('obj', 'return (' + v + ')');
} else {
return Ext.functionFactory('obj', 'return obj' + expr);
}
}
}
return function(obj) {
return obj[expr];
};
};
}()
});
I have changed Slava Nadvorny's example so that it completely works for ExtJS 4.1.1.
New extended class of Ext.data.reader.Json is below:
Ext.define('Ext.data.reader.SafeJson', {
extend: 'Ext.data.reader.Json',
alias : 'reader.safejson',
/**
* @private
* Returns an accessor function for the given property string. Gives support for properties such as the following:
* 'someProperty'
* 'some.property'
* 'some["property"]'
* This is used by buildExtractors to create optimized extractor functions when casting raw data into model instances.
*/
createAccessor: (function() {
var re = /[\[\.]/;
return function(expr) {
if (Ext.isEmpty(expr)) {
return Ext.emptyFn;
}
if (Ext.isFunction(expr)) {
return expr;
}
if (this.useSimpleAccessors !== true) {
var i = String(expr).search(re);
if (i >= 0) {
if (i > 0) { // Check all property chain for existence. Return null if any level does not exist.
var a = [];
var l = expr.split('.');
var r = '';
for (var w in l) {
r = r + '.' + l[w];
a.push('obj' + r);
}
var v = "(" + a.join(" && ") + ") ? obj." + expr + " : null";
return Ext.functionFactory('obj', 'return (' + v + ')');
} else {
return Ext.functionFactory('obj', 'return obj' + (i > 0 ? '.' : '') + expr);
}
}
}
return function(obj) {
return obj[expr];
};
};
}()),
/**
* @private
* @method
* Returns an accessor expression for the passed Field. Gives support for properties such as the following:
*
* - 'someProperty'
* - 'some.property'
* - 'some["property"]'
*
* This is used by buildExtractors to create optimized on extractor function which converts raw data into model instances.
*/
createFieldAccessExpression: (function() {
var re = /[\[\.]/;
return function(field, fieldVarName, dataName) {
var me = this,
hasMap = (field.mapping !== null),
map = hasMap ? field.mapping : field.name,
result,
operatorSearch;
if (typeof map === 'function') {
result = fieldVarName + '.mapping(' + dataName + ', this)';
} else if (this.useSimpleAccessors === true || ((operatorSearch = String(map).search(re)) < 0)) {
if (!hasMap || isNaN(map)) {
// If we don't provide a mapping, we may have a field name that is numeric
map = '"' + map + '"';
}
result = dataName + "[" + map + "]";
} else {
if (operatorSearch > 0) {
var a = [];
var l = map.split('.');
var r = '';
for (var w in l) {
r = r + '.' + l[w];
a.push(dataName + r);
}
result = "("+a.join(" && ")+") ? "+dataName+"."+map+" : null";
} else {
result = dataName + map;
}
}
return result;
};
}())
});
So you can successfully processing nested JSON-data with null nodes.
Example of JSON:
{
root: [{
id: 1,
name: {
name: "John",
phone: "123"
},
},
{
id: 4,
name: null,
},
]
}
Working example with test data you can find here: http://jsfiddle.net/8Ftag/
精彩评论