In its second innings, World Wide Web has introduced a newer approach to interact, organize & categorize information. With new Web 2.0 sites cropping up all over the place, the value of tools (& libraries) coming up to facilitate creativity and giving browser a bigger role to play in business interaction are talk of the town for the developers all around the world.

Apart from Ext JS library (http://extjs.com/), JackBuilder (JackBe), Flex (Adobe), GWT (Google), GI (Tibco) are other few Ajaxified GUI development tools that come to my mind, serving the similar cause. This article is first up in the series of Web 2.0 technologies that we will continue, and star of the show today is ext js.

There are already a few good articles available on ext js forum that talk about integrating Ext with DWR. Here’s one that I would recommend: http://extjs.com/forum/showthread.php?t=5586. Taking this further, the scope of this article would be creating a Data Grid (using Ext) for CRUD operations. Refer Ext API docs at http://extjs.com/deploy/dev/docs/. The package you need to emphasize for this article is Ext.data.*

1. Ext Data Grid (Ext.grid.GridPanel) can be percieved as a Table where each row is a Record (Ext.data.Record). These records will be fetched from the server and cached using Ext.data.Store object.

2. Ext.data.DataProxy, an abstract class extended by Ext.data.DWRProxy (refer DWR article from the link mentioned above), is the proxy configured for Ext.data.Store object to fetch data objects from server.

3. Now this store object is totally agnostic to the format of the data returned by the Proxy. This allow developer provide their own configured implementation of Ext.data.DataReader to convert these data objects into records and make them available.

Lets start on how one can create a proxy to be used by GridPanel.

ds = new Ext.data.Store({
    proxy: new Ext.data.DWRProxy(., true),
    reader: new Ext.data.ListRangeReader({
        id: 'field1',
        totalProperty: 'totalSize'
        }, Ext.data.Record.create([{
                name: "field1",
                mapping: "field1",
                type: "int"
            }, {
                name: "field2",
                mapping: "field2",
                type: "string"
           }]
        )
    )
});

To instantiate Ext.data.Store, the config object passed to the constructor included two properties; proxy & reader.

  • The property proxy is an instance of Ext.data.DWRProxy. As I said before, this being an extension of the DWR article I have already referenced, so my DWRProxy implementation remains same. Other subclasses of Ext.data.DataProxy (provided by ext js) are Ext.data.HttpProxy, Ext.data.MemoryProxy, Ext.data.ScriptTagProxy.
  • The property reader is instantiated as Ext.data.ListRangeReader. The reader object is chosen according to the format of resultset that your dwr method returns. Other extensions of Ext.data.DataReader are Ext.data.JsonReader, Ext.data.XmlReader & Ext.data.ArrayReader.

Every Reader is different in a way the format used by the server to return the data objects alongwith the addon properties needed like, total number of records etc. The constructor for a DataReader needs two things. A config object and a Record definition. The config object includes:

  • id to specify which field will be used as the identifier for each row.
  • totalProperty to specify which field contains information about total number of records the server returns.

The other argument, Record object, is an array of objects which provides mapping of property elements in data object to those in a grid record.

To make it more clearer, the result for which a ListRangeReader is appropriate looks like this:

{
    data: [{
        "field1": 1001,
        "field2": "data1"
    },{
        "field1": 1010,
        "field2": "data2"
    }],
    totalSize: 2
}

For JsonReader, check out http://extjs.com/deploy/dev/docs/output/Ext.data.JsonReader.html

Thanks to Ext API docs, creating Grid comes easy. The instantiation is self-informative enough to get in one’s head.

grid = new Ext.grid.GridPanel({
            el: "div_to_render",
            autoScroll: true,
            autoHeight: true,
            autoWidth: true,
            ds: ds,
            cm: new Ext.grid.ColumnModel([{
                header: 'Field1 Header',
                width: 250,
                sortable: true,
                dataIndex: 'field1'
            }, {
                header: 'Field2 Header',
                width: 250,
                sortable: true,
                dataIndex: 'field2'
            }]),
            sm: new Ext.grid.RowSelectionModel({
                singleSelect: true,
                listeners: {
                     rowselect: function(smObj, rowIndex, record) {
                         selRecordStore = record;
                    }
               }
            }),
            autoSizeColumns: true,
            trackMouseOver: true,

            tbar: [new Ext.Toolbar.Button({
                        text: 'Add',
                        handler: function(){
                        //Load New Form
                     }
            }), new Ext.Toolbar.Button({
                        text: 'Edit',
                        handler: function(){
                        //Load New Form
                        //Load Data

                        form.loadRecord(selRecordStore);
                  }
            }), new Ext.Toolbar.Button({
                        text: 'Delete',
                        handler: function(){
                        //Call for Delete for the record with this identifier
                        var id = selRecordStore["field1"]
                }
            })],

            bbar: new Ext.PagingToolbar({
                        pageSize: 2,
                        store: ds,
                        displayInfo: true,
                        displayMsg: 'Displaying Records {0} - {1} of {2}',
                        emptyMsg: "No Records to display",
                        items: ['-']
            })
});

Wondering, if I haven’t deviated away from the scope of this write up, notice that I have configured a listener for the Grid Selection Model which stores the reference of the records mapped for the row selected. This record is used by Toolbar Button handler for the actions specified.

This concludes my say on using Ajax based Ext JS Data Grid which looks difficult to use, first time u look at it, but provide us various features to configure, like Paging, Toolbar etc.

Note: For this being an introductory article to startup, I have tried my best to stay focussed on my scope. Based on the reviews/responses, I can follow it up with a working example.

References:
1. Ext JS Forum
2. Ext JS API Documentation