Clear Up
SharpKit Reference

Ext.data.reader Namespace

Download SDK: SharpKit.ExtJs.zip

Classes

Name Description
Array

Data reader class to create an Array of Ext.data.Model objects from an Array. Each element of that Array represents a row of data fields. The fields are pulled into a Record object using as a subscript, the mapping property of the field definition if it exists, or the field's ordinal position in the definition.

Example code:

  
Employee = Ext.define('Employee', {
            extend: 'Ext.data.Model',
            fields: [
            'id',
            {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
            {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
            ]
            });
            var myReader = new Ext.data.reader.Array({
            model: 'Employee'
            }, Employee);
            

This would consume an Array like this:

  
[ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
            
ArrayConfig
ArrayEvents
Json

The JSON Reader is used by a Proxy to read a server response that is sent back in JSON format. This usually happens as a result of loading a Store - for example we might create something like this:

  
    Ext.define('User', {
            extend: 'Ext.data.Model',
            fields: ['id', 'name', 'email']
            });
            var store = Ext.create('Ext.data.Store', {
            model: 'User',
            proxy: {
            type: 'ajax',
            url : 'users.json',
            reader: {
            type: 'json'
            }
            }
            });
            

The example above creates a 'User' model. Models are explained in the Model docs if you're not already familiar with them.

We created the simplest type of JSON Reader possible by simply telling our Store's Proxy that we want a JSON Reader. The Store automatically passes the configured model to the Store, so it is as if we passed this instead:

  
reader: {
            type : 'json',
            model: 'User'
            }
            

The reader we set up is ready to read data from our server - at the moment it will accept a response like this:

  
[
            {
            "id": 1,
            "name": "Ed Spencer",
            "email": "ed@sencha.com"
            },
            {
            "id": 2,
            "name": "Abe Elias",
            "email": "abe@sencha.com"
            }
            ]
            

Reading other JSON formats

If you already have your JSON format defined and it doesn't look quite like what we have above, you can usually pass JsonReader a couple of configuration options to make it parse your format. For example, we can use the root configuration to parse data that comes back like this:

  
{
            "users": [
            {
            "id": 1,
            "name": "Ed Spencer",
            "email": "ed@sencha.com"
            },
            {
            "id": 2,
            "name": "Abe Elias",
            "email": "abe@sencha.com"
            }
            ]
            }
            

To parse this we just pass in a root configuration that matches the 'users' above:

  
reader: {
            type: 'json',
            root: 'users'
            }
            

Sometimes the JSON structure is even more complicated. Document databases like CouchDB often provide metadata around each record inside a nested structure like this:

  
{
            "total": 122,
            "offset": 0,
            "users": [
            {
            "id": "ed-spencer-1",
            "value": 1,
            "user": {
            "id": 1,
            "name": "Ed Spencer",
            "email": "ed@sencha.com"
            }
            }
            ]
            }
            

In the case above the record data is nested an additional level inside the "users" array as each "user" item has additional metadata surrounding it ('id' and 'value' in this case). To parse data out of each "user" item in the JSON above we need to specify the record configuration like this:

  
reader: {
            type  : 'json',
            root  : 'users',
            record: 'user'
            }
            

Response MetaData

The server can return metadata in its response, in addition to the record data, that describe attributes of the data set itself or are used to reconfigure the Reader. To pass metadata in the response you simply add a metaData attribute to the root of the response data. The metaData attribute can contain anything, but supports a specific set of properties that are handled by the Reader if they are present:

  • root: the property name of the root response node containing the record data
  • idProperty: property name for the primary key field of the data
  • totalProperty: property name for the total number of records in the data
  • successProperty: property name for the success status of the response
  • messageProperty: property name for an optional response message
  • fields: Config used to reconfigure the Model's fields before converting the response data into records

An initial Reader configuration containing all of these properties might look like this ("fields" would be included in the Model definition, not shown):

  
reader: {
            type : 'json',
            root : 'root',
            idProperty     : 'id',
            totalProperty  : 'total',
            successProperty: 'success',
            messageProperty: 'message'
            }
            

If you were to pass a response object containing attributes different from those initially defined above, you could use the metaData attribute to reconifgure the Reader on the fly. For example:

  
{
            "count": 1,
            "ok": true,
            "msg": "Users found",
            "users": [{
            "userId": 123,
            "name": "Ed Spencer",
            "email": "ed@sencha.com"
            }],
            "metaData": {
            "root": "users",
            "idProperty": 'userId',
            "totalProperty": 'count',
            "successProperty": 'ok',
            "messageProperty": 'msg'
            }
            }
            

You can also place any other arbitrary data you need into the metaData attribute which will be ignored by the Reader, but will be accessible via the Reader's metaData property (which is also passed to listeners via the Proxy's metachange event (also relayed by the store). Application code can then process the passed metadata in any way it chooses.

A simple example for how this can be used would be customizing the fields for a Model that is bound to a grid. By passing the fields property the Model will be automatically updated by the Reader internally, but that change will not be reflected automatically in the grid unless you also update the column configuration. You could do this manually, or you could simply pass a standard grid column config object as part of the metaData attribute and then pass that along to the grid. Here's a very simple example for how that could be accomplished:

  
// response format:
            {
            ...
            "metaData": {
            "fields": [
            { "name": "userId", "type": "int" },
            { "name": "name", "type": "string" },
            { "name": "birthday", "type": "date", "dateFormat": "Y-j-m" },
            ],
            "columns": [
            { "text": "User ID", "dataIndex": "userId", "width": 40 },
            { "text": "User Name", "dataIndex": "name", "flex": 1 },
            { "text": "Birthday", "dataIndex": "birthday", "flex": 1, "format": 'Y-j-m', "xtype": "datecolumn" }
            ]
            }
            }
            

The Reader will automatically read the meta fields config and rebuild the Model based on the new fields, but to handle the new column configuration you would need to handle the metadata within the application code. This is done simply enough by handling the metachange event on either the store or the proxy, e.g.:

  
var store = Ext.create('Ext.data.Store', {
            ...
            listeners: {
            'metachange': function(store, meta) {
            myGrid.reconfigure(store, meta.columns);
            }
            }
            });
            
JsonConfig
JsonEvents
Reader

Readers are used to interpret data to be loaded into a Model instance or a Store - often in response to an AJAX request. In general there is usually no need to create a Reader instance directly, since a Reader is almost always used together with a Proxy, and is configured using the Proxy's reader configuration property:

  
    Ext.create('Ext.data.Store', {
            model: 'User',
            proxy: {
            type: 'ajax',
            url : 'users.json',
            reader: {
            type: 'json',
            root: 'users'
            }
            },
            });
            

The above reader is configured to consume a JSON string that looks something like this:

  
{
            "success": true,
            "users": [
            { "name": "User 1" },
            { "name": "User 2" }
            ]
            }
            

Loading Nested Data

Readers have the ability to automatically load deeply-nested data objects based on the associations configured on each Model. Below is an example demonstrating the flexibility of these associations in a fictional CRM system which manages a User, their Orders, OrderItems and Products. First we'll define the models:

  
    Ext.define("User", {
            extend: 'Ext.data.Model',
            fields: [
            'id', 'name'
            ],
            hasMany: {model: 'Order', name: 'orders'},
            proxy: {
            type: 'rest',
            url : 'users.json',
            reader: {
            type: 'json',
            root: 'users'
            }
            }
            });
            Ext.define("Order", {
            extend: 'Ext.data.Model',
            fields: [
            'id', 'total'
            ],
            hasMany  : {model: 'OrderItem', name: 'orderItems', associationKey: 'order_items'},
            belongsTo: 'User'
            });
            Ext.define("OrderItem", {
            extend: 'Ext.data.Model',
            fields: [
            'id', 'price', 'quantity', 'order_id', 'product_id'
            ],
            belongsTo: ['Order', {model: 'Product', associationKey: 'product'}]
            });
            Ext.define("Product", {
            extend: 'Ext.data.Model',
            fields: [
            'id', 'name'
            ],
            hasMany: 'OrderItem'
            });
            

This may be a lot to take in - basically a User has many Orders, each of which is composed of several OrderItems. Finally, each OrderItem has a single Product. This allows us to consume data like this:

  
{
            "users": [
            {
            "id": 123,
            "name": "Ed",
            "orders": [
            {
            "id": 50,
            "total": 100,
            "order_items": [
            {
            "id"      : 20,
            "price"   : 40,
            "quantity": 2,
            "product" : {
            "id": 1000,
            "name": "MacBook Pro"
            }
            },
            {
            "id"      : 21,
            "price"   : 20,
            "quantity": 3,
            "product" : {
            "id": 1001,
            "name": "iPhone"
            }
            }
            ]
            }
            ]
            }
            ]
            }
            

The JSON response is deeply nested - it returns all Users (in this case just 1 for simplicity's sake), all of the Orders for each User (again just 1 in this case), all of the OrderItems for each Order (2 order items in this case), and finally the Product associated with each OrderItem. Now we can read the data and use it as follows:

  
var store = Ext.create('Ext.data.Store', {
            model: "User"
            });
            store.load({
            callback: function() {
            //the user that was loaded
            var user = store.first();
            console.log("Orders for " + user.get('name') + ":")
            //iterate over the Orders for each User
            user.orders().each(function(order) {
            console.log("Order ID: " + order.getId() + ", which contains items:");
            //iterate over the OrderItems for each Order
            order.orderItems().each(function(orderItem) {
            //we know that the Product data is already loaded, so we can use the synchronous getProduct
            //usually, we would use the asynchronous version (see Ext.data.association.BelongsTo)
            var product = orderItem.getProduct();
            console.log(orderItem.get('quantity') + ' orders of ' + product.get('name'));
            });
            });
            }
            });
            

Running the code above results in the following:

  
Orders for Ed:
            Order ID: 50, which contains items:
            2 orders of MacBook Pro
            3 orders of iPhone
            
ReaderConfig
ReaderEvents
Xml

The XML Reader is used by a Proxy to read a server response that is sent back in XML format. This usually happens as a result of loading a Store - for example we might create something like this:

  
    Ext.define('User', {
            extend: 'Ext.data.Model',
            fields: ['id', 'name', 'email']
            });
            var store = Ext.create('Ext.data.Store', {
            model: 'User',
            proxy: {
            type: 'ajax',
            url : 'users.xml',
            reader: {
            type: 'xml',
            record: 'user',
            root: 'users'
            }
            }
            });
            

The example above creates a 'User' model. Models are explained in the Model docs if you're not already familiar with them.

We created the simplest type of XML Reader possible by simply telling our Store's Proxy that we want a XML Reader. The Store automatically passes the configured model to the Store, so it is as if we passed this instead:

  
reader: {
            type : 'xml',
            model: 'User',
            record: 'user',
            root: 'users'
            }
            

The reader we set up is ready to read data from our server - at the moment it will accept a response like this:

  
<?xml version="1.0" encoding="UTF-8"?>
            <users>
            <user>
            <id>1</id>
            <name>Ed Spencer</name>
            <email>ed@sencha.com</email>
            </user>
            <user>
            <id>2</id>
            <name>Abe Elias</name>
            <email>abe@sencha.com</email>
            </user>
            </users>
            

First off there's root option to define the root node <users> (there should be only one in a well-formed XML document). Then the XML Reader uses the configured record option to pull out the data for each record - in this case we set record to 'user', so each <user> above will be converted into a User model.

Note that XmlReader doesn't care whether your root and record elements are nested deep inside a larger structure, so a response like this will still work:

  
<?xml version="1.0" encoding="UTF-8"?>
            <deeply>
            <nested>
            <xml>
            <users>
            <user>
            <id>1</id>
            <name>Ed Spencer</name>
            <email>ed@sencha.com</email>
            </user>
            <user>
            <id>2</id>
            <name>Abe Elias</name>
            <email>abe@sencha.com</email>
            </user>
            </users>
            </xml>
            </nested>
            </deeply>
            

Response metadata

The server can return additional data in its response, such as the total number of records and the success status of the response. These are typically included in the XML response like this:

  
<?xml version="1.0" encoding="UTF-8"?>
            <users>
            <total>100</total>
            <success>true</success>
            <user>
            <id>1</id>
            <name>Ed Spencer</name>
            <email>ed@sencha.com</email>
            </user>
            <user>
            <id>2</id>
            <name>Abe Elias</name>
            <email>abe@sencha.com</email>
            </user>
            </users>
            

If these properties are present in the XML response they can be parsed out by the XmlReader and used by the Store that loaded it. We can set up the names of these properties by specifying a final pair of configuration options:

  
reader: {
            type: 'xml',
            root: 'users',
            totalProperty  : 'total',
            successProperty: 'success'
            }
            

These final options are not necessary to make the Reader work, but can be useful when the server needs to report an error or if it needs to indicate that there is a lot of data available of which only a subset is currently being returned.

Response format

Note: in order for the browser to parse a returned XML document, the Content-Type header in the HTTP response must be set to "text/xml" or "application/xml". This is very important - the XmlReader will not work correctly otherwise.

XmlConfig
XmlEvents
© Copyright 2005-2011 SharpKit. All rights reserved.