2 * Ext JS Library 2.2.1
\r
3 * Copyright(c) 2006-2009, Ext JS, LLC.
\r
4 * licensing@extjs.com
\r
6 * http://extjs.com/license
\r
10 * @class Ext.data.JsonReader
\r
11 * @extends Ext.data.DataReader
\r
12 * Data reader class to create an Array of {@link Ext.data.Record} objects from a JSON response
\r
13 * based on mappings in a provided {@link Ext.data.Record} constructor.<br>
\r
17 var Employee = Ext.data.Record.create([
\r
18 {name: 'firstname'}, // Map the Record's "firstname" field to the row object's key of the same name
\r
19 {name: 'job', mapping: 'occupation'} // Map the "job" field to the row object's "occupation" key
\r
21 var myReader = new Ext.data.JsonReader({
\r
22 totalProperty: "results", // The property which contains the total dataset size (optional)
\r
23 root: "rows", // The property which contains an Array of row objects
\r
24 id: "id" // The property within each row object that provides an ID for the record (optional)
\r
28 * This would consume a JSON object of the form:
\r
33 { id: 1, firstname: 'Bill', occupation: 'Gardener' }, // a row object
\r
34 { id: 2, firstname: 'Ben' , occupation: 'Horticulturalist' } // another row object
\r
38 * <p>It is possible to change a JsonReader's metadata at any time by including a
\r
39 * <b><tt>metaData</tt></b> property in the data object. If this is detected in the
\r
40 * object, a {@link Ext.data.Store Store} object using this Reader will reconfigure
\r
41 * itself to use the newly provided field definition and fire its
\r
42 * {@link Ext.data.Store#metachange metachange} event. In
\r
43 * undergoing this change, the Store sets its {@link Ext.data.Store#sortInfo sortInfo} property
\r
44 * from the <tt>sortInfo</tt> property in the new metadata. Note that reconfiguring a Store
\r
45 * potentially invalidates objects which may refer to Fields or Records which no longer exist.</p>
\r
47 * <p>The <b><tt>metaData</tt></b> property may contain any of the configuration
\r
48 * options for this class. Additionally, it may contain a <b><tt>fields</tt></b>
\r
49 * property which the JsonReader will use as an argument to {@link Ext.data.Record#create}
\r
50 * to configure the layout of the Records which it will produce.<p>
\r
51 * Using the <b><tt>metaData</tt></b> property, and the Store's {@link Ext.data.Store#metachange metachange} event,
\r
52 * it is possible to have a Store-driven control initialize itself. The metachange
\r
53 * event handler may interrogate the <b><tt>metaData</tt></b> property (which
\r
54 * may contain any user-defined properties needed) and the <b><tt>metaData.fields</tt></b>
\r
55 * property to perform any configuration required.</p>
\r
57 * <p>To use this facility to send the same data as the above example without
\r
58 * having to code the creation of the Record constructor, you would create the
\r
59 * JsonReader like this:</p><pre><code>
\r
60 var myReader = new Ext.data.JsonReader();
\r
62 * <p>The first data packet from the server would configure the reader by
\r
63 * containing a metaData property as well as the data:</p><pre><code>
\r
66 totalProperty: 'results',
\r
71 {name: 'occupation'}
\r
76 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
\r
77 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' }
\r
81 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
\r
82 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
\r
83 * paged from the remote server.
\r
84 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
\r
85 * @cfg {String} root name of the property which contains the Array of row objects.
\r
86 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
\r
88 * Create a new JsonReader
\r
89 * @param {Object} meta Metadata configuration options.
\r
90 * @param {Object} recordType Either an Array of field definition objects as passed to
\r
91 * {@link Ext.data.Record#create}, or a {@link Ext.data.Record Record} constructor created using {@link Ext.data.Record#create}.
\r
93 Ext.data.JsonReader = function(meta, recordType){
\r
95 Ext.data.JsonReader.superclass.constructor.call(this, meta, recordType || meta.fields);
\r
97 Ext.extend(Ext.data.JsonReader, Ext.data.DataReader, {
\r
99 * This JsonReader's metadata as passed to the constructor, or as passed in
\r
100 * the last data packet's <b><tt>metaData</tt></b> property.
\r
105 * This method is only used by a DataProxy which has retrieved data from a remote server.
\r
106 * @param {Object} response The XHR object which contains the JSON data in its responseText.
\r
107 * @return {Object} data A data block which is used by an Ext.data.Store object as
\r
108 * a cache of Ext.data.Records.
\r
110 read : function(response){
\r
111 var json = response.responseText;
\r
112 var o = eval("("+json+")");
\r
114 throw {message: "JsonReader.read: Json object not found"};
\r
116 return this.readRecords(o);
\r
119 // private function a store will implement
\r
120 onMetaChange : function(meta, recordType, o){
\r
127 simpleAccess: function(obj, subsc) {
\r
134 getJsonAccessor: function(){
\r
136 return function(expr) {
\r
138 return(re.test(expr))
\r
139 ? new Function("obj", "return obj." + expr)
\r
144 return Ext.emptyFn;
\r
149 * Create a data block containing Ext.data.Records from a JSON object.
\r
150 * @param {Object} o An object which contains an Array of row objects in the property specified
\r
151 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
\r
152 * which contains the total size of the dataset.
\r
153 * @return {Object} data A data block which is used by an Ext.data.Store object as
\r
154 * a cache of Ext.data.Records.
\r
156 readRecords : function(o){
\r
158 * After any data loads, the raw JSON data is available for further custom processing. If no data is
\r
159 * loaded or there is a load exception this property will be undefined.
\r
165 this.meta = o.metaData;
\r
166 this.recordType = Ext.data.Record.create(o.metaData.fields);
\r
167 this.onMetaChange(this.meta, this.recordType, o);
\r
169 var s = this.meta, Record = this.recordType,
\r
170 f = Record.prototype.fields, fi = f.items, fl = f.length;
\r
172 // Generate extraction functions for the totalProperty, the root, the id, and for each field
\r
174 if(s.totalProperty) {
\r
175 this.getTotal = this.getJsonAccessor(s.totalProperty);
\r
177 if(s.successProperty) {
\r
178 this.getSuccess = this.getJsonAccessor(s.successProperty);
\r
180 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
\r
182 var g = this.getJsonAccessor(s.id);
\r
183 this.getId = function(rec) {
\r
185 return (r === undefined || r === "") ? null : r;
\r
188 this.getId = function(){return null;};
\r
191 for(var i = 0; i < fl; i++){
\r
193 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
\r
194 this.ef[i] = this.getJsonAccessor(map);
\r
198 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
\r
199 if(s.totalProperty){
\r
200 var v = parseInt(this.getTotal(o), 10);
\r
205 if(s.successProperty){
\r
206 var v = this.getSuccess(o);
\r
207 if(v === false || v === 'false'){
\r
212 for(var i = 0; i < c; i++){
\r
215 var id = this.getId(n);
\r
216 for(var j = 0; j < fl; j++){
\r
218 var v = this.ef[j](n);
\r
219 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue, n);
\r
221 var record = new Record(values, id);
\r
223 records[i] = record;
\r
228 totalRecords : totalRecords
\r