ExtJS and ASP.NET part 8 – Extjs Combobox and wcf

The most interesting component in Extjs is its ComboBox, it is so powerful that it has auto complete, filtering, paging features supported at configuration level. To be honest till today I still do not know the whole story about this control yet. There is always place for you to explore. But with bit of help and firsthand experience you can get a few grips of this control and might just start to use it in a few circumstances.

Here as usual I would like to clear a few misunderstandings and support that with prove-of-concept examples.

So buckle up let us get on with it

1. Remote or Local
There are tons of configuration points for this control, and some of them are death and life choices if you do not get them right. The first one I had struggled with was the idea of ‘local’ and ‘remote’ mode. I was thinking that no matter what the mode is, If I gave it a populated data store, it should just kick off from there. And it turns out not the case at all, the mode setting here is more important and dictating the control how and when to retrieve data from data store that must match with the mode setting.
First thing I would like to mention is as default the mode was set to remote. As you may or may not know that not setting mode explicitly means you are using the remote mode.
For local mode, combo box expects a preloaded data store, on the other hand for remote mode, the data store just has to be wired up to a remote source through url, a preloaded data store in remote mode will not work even it is already populated.
When the data is static, local or from a remote source, as long as it is preloaded, then use local mode, if you want to implement server side filtering, paging, like an auto complete, then use remote mode.

2. triggerAction, minChars, queryParam, allQuery,lastQuery
It is not hard to find the original documents for above concepts, but it is still very hard to fully understand what values these parameters should have, and what implications will be. As the framework is open source project, to some extent it makes inefficient documentation less intolerable, because there is always source code for you to investigate.

In case you want to understand how these values will affect the behaviours of combo box, there are two functions that I would recommend you have a look at , doQuery and onTriggerClick

From these two functions we can unlock all the mysteries that are surrounding the use of these parameter. Here is my two cents of worth

2.1. queryParam minChars and lastQuery
One of the confusing also the powerful feature for combo box is when you type characters in the dropdown box, the control will automatically do some filtering for you based on what you have typed in, it happens both to local and remote mode, for local mode, the list will be filtered according to characters that are typed in, but for remote mode, an ajax request is made to server with typed in characters under the parameter name of ‘query’ when its length exceeded minChars.
So minChars only relevant when mode is remote, the parameter name ‘query’ is controlled by queryParam as the default. The parameter name is important only to the server side to accept input, normally you would not want to change it. For details see my examples following.

Last query is not part of initially construction, so you do not need to worry about this when you first set up a combo box, as you can see from doQuery function, it is basically an internal variable used for caching, when you want to add some extra filtering functionalities other than the typed in characters, it is the variable to modify, and recommended place is in the event of beforequery.

2.2 triggerAction and allQuery
They only affect the onTriggerClick, that is when you click the dropdown box, as doQuery can also be triggered by typing, so these two parameters do not have any impact on typed in characters filtering. One foreseeable impact is when you have some characters in the dropdown box, you clicked the dropdown, a search will be started using the characters if triggerAction =’query’ , that is where triggerAction =’all’ always returns all items theory comes from, because when triggerAction=’all’, allQuery which default to blank is used.

If you are not confused by this stage then congratulations, even if you are, do not be afraid, keep reading, by copying the examples I presented you will be able to solve most of your requirements regarding to a combo box, and good news is you do not need to touch those parameters at all in most of the usual situations.

3. Server side paging
It is extremely easy to do server side paging, all you need to do is use remote mode, set the pagesize and properly program your server method to accept the params sent from control by adding arguments like start , limit, and query (this is available for all remote mode as the value of typed in characters) to your server method, and the return value to include information like total rows. Details see example below.

4 Examples

4.1. Combo mode local with a pure local store:

  var genres = new Ext.data.SimpleStore(
            {
                fields: ['id', 'genre'],
                data: [['1', 'Comedy'], ['2', 'Drama'], ['3', 'Action']]
            });

            var GenreCombo = new Ext.form.ComboBox({
                name: 'genre',
                fieldLabel: 'Genre',
                mode: 'local',
                store: genres,
                displayField: 'genre',
                width: 120,
                listeners: {
                    select: function (f, r, i) {
                        if (i == 1) {
                            Ext.Msg.prompt('New Genre', 'Name', Ext.emptyFn);
                        }
                    }
                }

            });

4.2. Combo mode local with preloaded remote store:

 var myparams = { 'id': 1 };

  var myStore2 = new Ext.data.JsonStore({
                // Load data at once
                //  autoLoad: true,
                // Override default http proxy settings
                proxy: new Ext.data.HttpProxy({
                    // Call web service method using GET syntax
                    url: 'Service1.svc/GetList',
                    method: 'GET'

                }),
                // Root variable 
                root: 'd',
                // Record identifier
                id: 'VPValue',
                // Fields declaration
                fields: ['VPValue', 'VPDes']
            });

            myStore2.load({
                params: myparams
            });


     var comboField1 = new Ext.form.ComboBox({
                fieldLabel: 'Combo Box',
                mode: 'local',
                anchor: '80%',
                store: myStore2,
                displayField: 'VPDes',
                valueField: 'VPValue',
                name: 'cb1'
            });


Server side of it


  [OperationContract]
    [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json)]
    public ValuePair[] GetList(int id)
    {
        List<ValuePair> result = new List<ValuePair>();
        for (int i = 0; i <= 9; i++)
        {
            result.Add(new ValuePair { VPValue = i, VPDes = "Item "+i.ToString()});
        }
        return result.ToArray();  
    }

public class ValuePair
    {
        public int VPValue { get; set; }
        public string VPDes { get; set; }
    }


4.3. Combo mode remote with a remote store:

var myStore2Remote = new Ext.data.JsonStore({
                // Load data at once
                //  autoLoad: true,
                // Override default http proxy settings
                proxy: new Ext.data.HttpProxy({
                    // Call web service method using GET syntax
                    url: 'Service1.svc/GetListRemote',
                    method: 'GET'

                }),
                // Root variable 
                root: 'd',
                // Record identifier
                id: 'VPValue',
                // Fields declaration
                fields: ['VPValue', 'VPDes'],
                listeners: { beforeload: SetParams }
            });

            function SetParams() {
                myStore2Remote.baseParams.id = 1;
            }


     var comboField2 = new Ext.form.ComboBox({
                fieldLabel: 'Remote Combo Box',
                anchor: '80%',
                mode: 'remote',
                 store: myStore2Remote,
                displayField: 'VPDes',
                valueField: 'VPValue',
                minChars: 0,
                name: 'cb2'
            });

Server side

  [OperationContract]
    [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json)]
    public ValuePair[] GetListRemote(int id,string query)
    {

        List<ValuePair> result = new List<ValuePair>();
      
            for (int i = 0; i <= 9; i++)
            {
                result.Add(new ValuePair { VPValue = i, VPDes = i.ToString() + " Item" });
            }
        return result.ToArray();
    }

Note that : query is the characters in field, the filtering is not implemented on the server, as it is fired every time field is changed, so normally only use a remote store when is a long list.

4.3. Combo mode remote with a remote store with paging:

    var myStore4Remote = new Ext.data.JsonStore({

                proxy: new Ext.data.HttpProxy({
                    // Call web service method using GET syntax
                    url: 'Service1.svc/GetListPaged',
                    method: 'GET'

                }),
                // Root variable 
                root: 'd.rows',

                totalProperty: 'd.total',
                // Record identifier
                id: 'VPValue',
                // Fields declaration
                fields: ['VPValue', 'VPDes'],
                listeners: { beforeload: function () {
                    myStore4Remote.baseParams.forumId = 1;
                }
                }
            });

     var comboField3 = new Ext.form.ComboBox({
                fieldLabel: 'Remote Combo Box Paged',
                anchor: '80%',
                mode: 'remote',
                store: myStore4Remote,
                displayField: 'VPDes',
                valueField: 'VPValue',
                pageSize: 20,
                minChars: 0,
                name: 'cb3'
            });


Server side

[OperationContract]
    [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json)]
    public ExtJsPageResult GetListPaged(int start, int limit, string query, int forumId)
    {
        List<ValuePair> result = new List<ValuePair>();
        for (int i = 0; i <= limit-1 ; i++)
        {
            result.Add(new ValuePair { VPValue = (start * limit + i), VPDes ="Forum "+forumId.ToString()+"Item " + (start * limit + i).ToString() });
        }

        return new ExtJsPageResult { total =98, rows = result.ToArray()};
    }


  [DataContract]
    public class ExtJsPageResult
    {
        [DataMember]
        public int  total { get; set; }
        [DataMember]
        public ValuePair[] rows { set; get; }
    }

A note about server returned value it has to have the total rows of whole data set for paging.

Tags: ,

This entry was posted on Monday, August 23rd, 2010 at 3:45 am and is filed under ASP.NET, Javascript. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply

*