开发者

ExtJS - null safe retrieval of complex objects using JsonReader

开发者 https://www.devze.com 2023-02-26 09:15 出处:网络
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.

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:

  1. use the convert()-mechanism of Ext.data.Field:

    {
        name:'status', 
        mapping: 'status',
        convert: function(status, data) {
            if (!Ext.isEmpty(status) && status.name) {
                return status.name;
            } else {
                return null;
            }
        }
    }
    
  2. 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/

0

精彩评论

暂无评论...
验证码 换一张
取 消