Иногда исходные данные для хранилища данных Ext.data.Store могут не соответствовать в точности модели данных Ext.data.Model, что приводит к невозможности их отображения в дальнейшем.
Например, если у нас есть такие исходные данные в формате JSON, то проблем со стороны Extjs нет:
1 2 3 4 5 6 |
[ {id: 1, name: {name:"John", phone: "123"}, description:"Fapfapfap"}, {id: 2, name: {name:"Danny", phone: "234"}, description:"Boobooboo"}, {id: 3, name: {name:"Tom", phone: "345"}, description:"Tralala"}, {id: 4, name: {name:"Jane", phone: "456"}, description:"Ololo"}, ] |
т.к. все данные соответствуют описанной модели:
1 2 3 4 5 6 7 8 9 |
Ext.define("Model", { extend: "Ext.data.Model", fields: [ {name: "id", type: "int"}, {name: "name.name"}, {name: "phone", mapping: "name.phone"}, {name: "descr", type: "string", mapping:'description'} ] }); |
Но как только, хотябы в одной из записей отсутствует поле учавствующее в маппинге (карта соответствий между данными и полями), то все данные игнорируются:
1 2 3 4 5 6 |
[ {id: 1, name: {name:"John", phone: "123"}, description:"Fapfapfap"}, {id: 2, name: {name:"Danny", phone: "234"}, description:"Boobooboo"}, {id: 3, name: {name:"Tom", phone: "345"}, description:"Tralala"}, {id: 4, description:"Ololo"}, ] |
Что хорошо видно на примере.
Загружаются: http://jsfiddle.net/elganz/3hwp3/5/
Не загружаются: http://jsfiddle.net/elganz/3hwp3/6/
Решение
Для решения таких проблем можно использовать улучшенный обработчик данных в формате Json. Для его применения достаточно просто в proxy хранилища заменить тип reader c json на safejson.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
Ext.define('Ext.ux.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; }; }()) }); |