January 28, 2011

Cascading Combo box in ExtJS

This week, two Techno Paper readers had approached me with questions on cascaded loading of combo box in ExtJS. Rather than replying them with mails, I decided to put it up for on the blog so other readers can also get it. In this tutorial I will explain how to cascade the loading of combo box options.


Cascading combo box can help in avoiding huge combo boxes. You can provide the user with a drill down of options that you offer and this helps them narrow down the options to select. When you have large data to display, it would be better to avoid combo boxes and go for a list view.

For now, let’s take a simple form where the user is asked to select geographical location & language. The selection of city is made by selecting country and region. So, we have three combo box:
  • To select region (Continent)
  • To select country
  • To select city
User does a drilldown on these three combos to finally select the city. First the user selects the continent. Selection triggers loading of all the countries in that continent. And similarly selection of country will trigger the loading of cities of that country.

Now, let’s get our hands dirty with the code. We will have a data store for each of the comobo boxes. In this tutorial, we will use Json store. You should be able to use any other store Ext JS library provide. Let me introduce the store for holding continents:
var mainStore = new Ext.data.JsonStore({
 autoLoad: true,
 url: '/GetContient',
 fields: ['item','value']
});
The store is very simple and straight forward. We set three properties of the json store. Unlike other dropdowns, the continent is starting point of our cascading. In order to load it along with the form, we will use autoLoad property of the stores. You need to define the url from which the store will be loaded & the fields array provides information on the fields.

The other two stores are slightly different. They will be loaded through selection of the respective drop downs. So, they are not initially loaded with values. Here are the stores for country and city:
var countryStore = new Ext.data.JsonStore({
 autoLoad: false,
 pruneModifiedRecords: true,
 url: '/GetCountry',
        fields: ['item', 'value']                   
});
     
var cityStore = new Ext.data.JsonStore({
 autoLoad: false,
        pruneModifiedRecords: true,
        url: '/GetCity',
 fields: ['item', 'value']                   
});
We have set pruneModifiedRecords property inorder to clear records each time the store is loaded. Now we have our stores ready. Let’s code our form and its fields.

Apart from the three drop downs, I will have a text field for keying in the language. We will render the directly onto the HTML document’s body tag. So, here is the code:
var Example = new Ext.Panel({
    title: 'Example of Cascading combos',
    renderTo: document.body,
    width: 400,       
    frame: true,
    items: [{
        xtype: 'form',
        url: '/FormSubmitURL',
        id: 'ex-form',                                                                      
        method: 'post',
        defaults: {
            anchor: '95%'
        },
        items: [{
            xtype: 'combo',
            fieldLabel: 'Continent',
     emptyText: 'Select a Continent',
            store: mainStore,                            
            editable: false,
            allowBlank: false,
            forceSelection: true,
            valueField: 'value',
            displayField: 'item',
            triggerAction: 'all',
            hiddenName: 'continent',
            id: 'continent',
  listeners: {        
          'select' : function(field,nval,oval) {
    countryStore.load({
                      params: {'id': nval.data.value }
             });
    }
   }
        }, {
   xtype: 'combo',
            fieldLabel: 'Country',
   emptyText: 'Select a Country',
            store: countryStore,
   mode: 'local',
            editable: false,
            allowBlank: false,
            forceSelection: true,
            valueField: 'value',
            displayField: 'item',
            triggerAction: 'all',
            hiddenName: 'country',
            id: 'country',
   listeners: {
    'select' : function(field,nval,oval) {
     cityStore.load({
                params: {'id': nval.data.value }
             });
    }
   }
  },{
   xtype: 'combo',
            fieldLabel: 'City',
   emptyText: 'Select a City',
            store: cityStore,
   mode: 'local',
            editable: false,
            allowBlank: false,
            forceSelection: true,
            valueField: 'value',
            displayField: 'item',
            triggerAction: 'all',
            hiddenName: 'city',
            id: 'city'       
  },{
   xtype: 'textfield',
            fieldLabel: 'Language',
            name: 'language',
            id: 'language'
        }],                        
        buttons: [{
            text: 'Submit',
            handler: function() {
    alert('Submit the form');
   }
        }]
    }]
});
Now, lets focus on one of the combo boxes. Notice how we cascade the loading of the combo boxes using the select event. The select event callback function provides us with all the information we need. It has three parameters and they are:
  1. The combo box
  2. The newly selected field record
  3. Numerical index value of old selection
From the callback’s parameters, we get the new selection information, which is used to load the country or city data store using the load method.

You can download the Javascript source code and try it. I have not included the any server side or ExtJS files with the package. Please provide your comments and suggestions. :)

Read other ExtJS related articles!

January 18, 2011

Working with .Net serialized dates in ExtJS

ASP.Net’s JSON serialize encodes DateTime instance as a string. If you return a JSON from a MVC contoller, you will notice your data encoded in the form:
\/Date(1295163209177)\/

This is basically nothing but Jan 16 2011 10:33:29! ExtJs components like data grid, datepicker do not consume this format and needs to be transformed.

Why does Microsoft serialize DateTime in this form?

One of the major disadvantages of using JSON is its lack of date/time literal. The support for date and time values is provided by the Date object in javascript. So, In order to represent the date and time, there are two options available:

1. To express the data as string
2. To express it in numerical form.

The numeric form would be the the number of milliseconds in Universal Coordinated Time (UTC) since epoch. But in either form, we still have the issue of not being able to identify it as date / time. In order to overcome this, MS came up with encoding DateTime values as string in the form:
\/Date(ticks)\/

How to fix it in ExtJS?

Deserializing in ExtJS can be done with the help of Date class. You can use the parseDate static method to convert the serialized date into Date object.
var dt = Date.parseDate(date,'M$');
dt.format('d/m/y');
The deserialized dates can be displayed in any desired format! :)

Read other ExtJS related articles!

January 11, 2011

Getting "Dive into HTML5" for Free!!!

There are many references available for HTML5. But, there is one reference you should not miss as a web developer.

Dive into HTML5 by Mark Pilgrim is free for the public. Site: http://diveintohtml5.org/

For those you need the hard copy, you can get the book titled HTML5: Up & Running by the same author (Costs around $18).

January 10, 2011

Creating toolbar in ExtJS Viewport

Building application UI using Ext JS can be complex and confusing for new comers. When you build applications, you usually make use of the border layout for placing different components onto the main screen of your application. In most of the cases you will require a toolbar with menus and buttons. But the viewport component has a catch.


Unlike the panel component of Ext JS, Viewport does not have a tbar option. So, you cannot attach a toolbar component into viewport. The best solution is to convert north region of your application to a toolbar.

To keep things simple, will have north, west and center regions of my border layout. I will also avoid handler methods and other actual content of the application. First lets simple define the application layout alone.
var application = new Ext.Viewport({
    renderTo: document.body,
    layout: 'border',
    items: [{
        region: 'north',
        border: false,
        frame: true,
        html: 'this is north'        
    }, {
        region: 'west',
        layout: 'fit',
        width: 200,
        border: true,
        frame: true,
        html: 'This is the left panel'
    }, {
        region: 'center',
        html: 'This is the center panel',
        frame: true,
        border: true
    }]
});
Once you have the layout, you just need to convert the north region into a toolbar. To do so, you will have to create a tbar instance in the north region’s panel. The complete code given below:
Ext.onReady(function(){
    Ext.QuickTips.init();
        
    var application = new Ext.Viewport({
        renderTo: document.body,
        layout: 'border',
        items: [{
            region: 'north',
            border: false,
            tbar: [{
                text: 'New',
                menu: [{
                    text: 'Add New X'
                }, {
                    text: 'Add New Y'
                }]
            }, {
                text: 'Refresh'
            }, {
                text: 'Tools'
            }, '->', {
                text: 'Options',
                iconCls: 'options_icon',
                menu: [{
                    text: 'User Info'
                }, {
                    text: 'Settings'
                }, {
                    text: 'Switch Theme'
                }]
            }, {
                text: 'Help'
            }, '-', {
                text: 'Logout'
            }]
        }, {
            region: 'west',
            layout: 'fit',
            width: 200,
            border: true,
            frame: true,
            html: 'This is the left panel'
        }, {
            region: 'center',
            html: 'This is the center panel',
            frame: true,
            border: true
        }]
    });    
});
You will have to add handlers for the buttons or menu you added to the toolbar. You can add the appropriate handler function to the property named handler. For example, let’s assume we are adding a handler to “Add New X” menu item:
text: 'New',
                menu: [{
                    text: 'Add New X',
      handler: function() {
Ext.Msg.alert(‘Alert’, 'Add new X item!');
} 
                }, {
                    text: 'Add New Y'
                }]
As always your ideas, doubts and comments are always welcome. Also share your experience on web technologies on Techno Paper facebook page!

Read other ExtJS related articles!