One of the most popular questions in ExtJs forums (stackoverflow) is how to extract data from non standard JSON and put it in store. First, I would like to suggest that you should avoid this trick. Try to speak with BackEnd developers and get appropriate JSON format for your application. However, if it is not possible, you can use the workarounds, which are described in this post.

ExtJs gives several possibilities to achieve this goal I will show only two of them:

  • Using transform method of the readers;
  • Using mapping of the models;
  • Making row AJAX request and filling the store; Very bad idea!

For the transform method of the reader I have used the following JSON:

{
    "users": [{
        "name": "Lisa",
        "surname": "Simpson"
    }, {
        "name": "Bart",
        "surname": "Simpson"
    }, {
        "name": "Homer",
        "surname": "Simpson"
    }, {
        "name": "Marge",
        "surname": "Simpson"
    }]
}

To change the JSON tag names to model field names I have used mapping property. This property can get function as a parameter with a root’s item and string. I have used a string to make the sample simpler.

Ext.define('app.model.ModelMappingUser', {
    extend: 'Ext.data.Model',
    fields: [{
        name: 'firstName',
        type: 'string',
        mapping: 'name'
    }, {
        name: 'lastName',
        type: 'string',
        mapping: 'surname'
    }]
});

In ideal case we must keep the entity name in all the layers of our application. If you have a ‘First Name’ column in the grid, the dataIndex of the column, model field name, JSON property name, variable names in the BackEnd code and even the column name in the database when it is possible must be called also ‘firstName’. In this case the data tracking will be much easier.

The second JSON has an over-nesting.

{
    "users": [{
        "names": {
            "nameOne": "Lisa",
            "nameTwo": "Simpson"
        }
    }, {
        "names": {
            "nameOne": "Bart",
            "nameTwo": "Simpson"
        }
    }, {
        "names": {
            "nameOne": "Homer",
            "nameTwo": "Simpson"
        }
    }, {
        "names": {
            "nameOne": "Marge",
            "nameTwo": "Simpson"
        }
    }]
}

The transformation was resolved with reader’s transform property.

Ext.define('app.store.ReaderTransformationUsers', {
    extend: 'Ext.data.Store',

    model: 'app.model.ReaderTransformationUser',

    proxy: {
        type: 'ajax',
        url : 'ReaderTransformationUsers.json',
        reader: {
            type: 'json',
            rootProperty: 'users',
            transform: {
                fn: function(data) {
                    var users = [];
                    Ext.Array.each(data.users, function(user) {
                        users.push({
                            'firstName': user.names.nameOne,
                            'lastName': user.names.nameTwo
                        });
                    }, this);
                    return users;
                },
                scope: this
            }
        }
    },
    autoLoad: true
});

This logic must be moved to the view of the BackEnd. The JSON format must be changed if possible; and in case if it is already used by another application an appropriate new service, which will also be under protection of automatic tests, should be created.

Such kind of workarounds breaks the KISS and YAGNI principles. They increase complexity and instability of all the system.

Another reason, due to the difficulty of creating and maintaining GUI-based automation testing, it is better to move all possibly movable logic to BackEnd.

It is often said that the devil is in details.