1

With Oleg and many websites help I have been working on getting cascading data bound drop downs functioning in jqGrid

I have three drop downs: Customer > Project > Task. Changing Customer should reload Project with that Customers Projects. Changing Projects should reload Tasks with that Projects Tasks.

I have actually got Project to reload with that Customers tasks by creating a change event handler in Customer which in turn calls getJson against a URL and then replaces the contents of the Project drop down with the new options. It works great.

I then applied this same logic to the Project drop down, but the Project event does not appear to fire. I have observed the following when changing the Project drop down:

  1. The Task drop down does not change
  2. The Task Json controller event is not called (it is meant to be called by getJSON in the Project change event)
  3. In Firebug, in the Network monitor, the call and response to the Task Json controller event does not appear.
  4. In Firebug it does not hit a breakpoint that I set in the Project change event handler

The Customer event handler however works perfectly, and performs all of the above 4 points as expected when I change the Customer.

I am fairly certain it is not firing the change event against the Project drop down.

If I run the web page and edit and change the Project drop down value as my very first action, it does not fire the project event handler, so I don't think it is the Customer event resetting the Project event handler.

So, does anyone know why my Customer change event is called but my Project one is not?

Is there a way I can inspect the DOM or something and see if my event has been attached at runtime? is that the way it works?

I am using jqGrid 4.4.1

My jqGrid is setup this way:

  • Uses inline editing
  • click to select dblclick to edit
  • A datepicker is attached the date column
  • Upon edit I get the select db key value out of hidden fields but I'm hoping I can remove that.
  • I have three selects next to each other

Here is the my jqGrid definition

$(document).ready(
    function () {
        // This is executed as soon as the DOM is loaded and before the page contents are loaded
        var lastsel;
        // $ is short for JQuery which is in turn a super overloaded function that does lots of things.
        // # means select an element by its ID name, i.e. below we have <table id="ts"
        // .jqGrid means attach a jqGrid 'thing' to all elements that have ts as their element name (there's only one)
        // jqGrid is a thing defined in the jqGrid javascript file
        $("#ts").jqGrid({
            //=============
            // Grid Setup
            url: 'Timesheet/GridData/',
            datatype: 'json',
            mtype: 'GET',
            pager: $('#pager'),
            rowNum: 30,
            rowList: [10, 20, 30, 40, 80],
            viewrecords: true,
            caption: 'Timesheet',
            height: 450,
            // Column definition
            colNames: ['hCustomer_ID', 'hProject_ID', 'hTask_ID', 'Date', 'Customer', 'Project', 'Task', 'Description', 'Hours', '$'],
            colModel: [
              { name: 'hCustomer_ID', index: 'hCustomer_ID', editable: false, hidden: true },
              { name: 'hProject_ID', index: 'hProject_ID', editable: false, hidden: true },
              { name: 'hTask_ID', index: 'hTask_ID', editable: false, hidden: true },
              { name: 'tsdate', index: 'tsdate', width: 80, editable: true, datefmt: 'yyyy-mm-dd' },
            // Defintion for customer column
              {name: 'Customer', index: 'Customer', width: 250, align: 'left', editable: true, edittype: "select",
              editoptions: {
                  // Default URL used to populate drop down when the column goes into edit mode  
                  dataUrl: 'Timesheet/CustomerList',
                  dataEvents: [
                      {
                          // this is the change handler. This is called when the customer is changed
                          type: 'change',
                          fn: function (e) {
                              // get a reference to the project and task drop downs on this same row
                              var eProject = '#' + $(this).attr("id").replace("_Customer", "_Project");
                              var eTask = '#' + $(this).attr("id").replace("_Customer", "_Task");
                              // Call getJSON to get data from a URL and process it with a callback function
                              $.getJSON(
                              // the URL to call
                                'Timesheet/ProjectListJSON',
                              // the parameter(s) to pass to the URL
                                {Customer_ID: this.value },
                              // The callback function. The results of the JSON call are passed into jData
                                function (jData) {
                                    var selectHtml = ""
                                    // Repopulate the project drop down with the results of the JSON call
                                    $.each(
                                        jData,
                                        function (jdIndex, jdData) {
                                            selectHtml = selectHtml + "<option value='" + jdData.Value + "'>" + jdData.Text + "</option>";
                                        });
                                    // dont use innerHTML as it is not supported properly by IE
                                    // insted use jQuery html to change the select list options
                                    $(eProject).html(selectHtml);
                                    // blank out tasks
                                    $(eTask).html("");
                                } // END getJSON callback function definition
                              ); // END getJSON function call
                          } // END change event definition
                      }] // END dataEvents definition
              } // END editoptions list
          }, // END Customer jqGrid field definition
            // Definition for Project drop down
          {name: 'Project', index: 'Project', width: 250, align: 'left', editable: true, edittype: "select",
          editoptions: {
              dataUrl: 'Timesheet/ProjectList',
              dataEvents: [
                      {
                          type: 'change',
                          fn: function (e) {
                              var eTask = '#' + $(this).attr("id").replace("_Project", "_Task");
                              $.getJSON(
                                'Timesheet/TaskListJSON',
                                { CustomerProject_ID: this.value },
                                function (jData) {
                                    var selectHtml = "";
                                    $.each(
                                        jData,
                                        function (jdIndex, jdData) {
                                            selectHtml = selectHtml + "<option value='" + jdData.Value + "'>" + jdData.Text + "</option>";
                                        });
                                        $(eTask).html(selectHtml);
                                } // END getJSON callback function definition
                              ); // END getJSON function call
                          } // END change event handler definition
                      }] // END dataevents definition
          } // END editoptions list
      }, // END Project jqGrid field definition
              {name: 'Task', index: 'Task', width: 250, align: 'left', editable: true, edittype: "select", editoptions: { dataUrl: 'Timesheet/TaskList'} },
              { name: 'Desc', index: 'Desc', width: 300, align: 'left', editable: true },
              { name: 'Hours', index: 'Hours', width: 50, align: 'left', editable: true },
              { name: 'Charge', index: 'Charge', edittype: 'checkbox', width: 18, align: 'center', editoptions: { value: "0:1" }, formatter: "checkbox", formatoptions: { disabled: false }, editable: true }
            ],
            //=============
            // Grid Events
            // when selecting, undo anything else
            onSelectRow: function (rowid, iRow, iCol, e) {
                if (rowid && rowid !== lastsel) {
                    // $(this).jqGrid('restoreRow', lastsel);
                    lastsel = rowid;
                }
            },
            // double click to edit
            ondblClickRow: function (rowid, iRow, iCol, e) {
                // browser independent stuff
                if (!e) e = window.event;
                var element = e.target || e.srcElement

                // When editing, change the drop down datasources to filter on the current parent
                $(this).jqGrid('setColProp', 'Project', { editoptions: { dataUrl: 'Timesheet/ProjectList?Customer_ID=' + $(this).jqGrid('getCell', rowid, 'hCustomer_ID')} });
                $(this).jqGrid('setColProp', 'Task', { editoptions: { dataUrl: 'Timesheet/TaskList?CustomerProject_ID=' + $(this).jqGrid('getCell', rowid, 'hProject_ID')} });

                // Go into edit mode (automatically moves focus to first field)
                // Use setTimout to apply the focus and datepicker after the first field gets the focus
                $(this).jqGrid(
                    'editRow',
                    rowid,
                    {
                        keys: true,
                        oneditfunc: function (rowId) {
                            setTimeout(function () {
                                $("input, select", element).focus();
                                $("#" + rowId + "_tsdate").datepicker({ dateFormat: 'yy-mm-dd' });
                            }, 50);
                        }
                    }
                );

            },  // end ondblClickRow event handler
            postData:
                {
                    startDate: function () { return $('#startDate').val(); }
                }
        }); // END jQuery("#ts").jqGrid

        $("#ts").jqGrid('navGrid', '#pager', { view: false, edit: false, add: false, del: false, search: false });
        $("#ts").jqGrid('inlineNav', "#pager");

    });                                       // END jQuery(document).ready(function () {

FIXED CODE HERE

I moved the change event handler definition out of the column definition and into the dblclick event handler. It's still not perfect. I'm sure there is some overhead in attaching the event handler every time, and when Customer is changed, it updates and selects the first Project but clears the Tasks.

$(document).ready(
    function () {
        // This is executed as soon as the DOM is loaded and before the page contents are loaded
        var lastsel;
        // $ is short for JQuery which is in turn a super overloaded function that does lots of things.
        // # means select an element by its ID name, i.e. below we have <table id="ts"
        // .jqGrid means attach a jqGrid 'thing' to all elements that have ts as their element name (there's only one)
        // jqGrid is a thing defined in the jqGrid javascript file
        $("#ts").jqGrid({
            //=============
            // Grid Setup
            url: 'Timesheet/GridData/',
            datatype: 'json',
            mtype: 'GET',
            pager: $('#pager'),
            rowNum: 30,
            rowList: [10, 20, 30, 40, 80],
            viewrecords: true,
            caption: 'Timesheet',
            height: 450,
            // Column definition
            colNames: ['hCustomer_ID', 'hProject_ID', 'hTask_ID', 'Date', 'Customer', 'Project', 'Task', 'Description', 'Hours', '$'],
            colModel: [
              { name: 'hCustomer_ID', index: 'hCustomer_ID', editable: false, hidden: true },
              { name: 'hProject_ID', index: 'hProject_ID', editable: false, hidden: true },
              { name: 'hTask_ID', index: 'hTask_ID', editable: false, hidden: true },
              { name: 'tsdate', index: 'tsdate', width: 80, editable: true, datefmt: 'yyyy-mm-dd' },
            // Defintion for customer column
              {name: 'Customer', index: 'Customer', width: 250, align: 'left', editable: true, edittype: "select",
              editoptions: {
                  // Default URL used to populate drop down when the column goes into edit mode  
                  dataUrl: 'Timesheet/CustomerList',
                  dataEvents: [
                      {
                          // this is the change handler. This is called when the customer is changed
                          type: 'change',
                          fn: function (e) {
                              // get a reference to the project and task drop downs on this same row
                              var eProject = '#' + $(this).attr("id").replace("_Customer", "_Project");
                              var eTask = '#' + $(this).attr("id").replace("_Customer", "_Task");
                              // Call getJSON to get data from a URL and process it with a callback function
                              $.getJSON(
                              // the URL to call
                                'Timesheet/ProjectListJSON',
                              // the parameter(s) to pass to the URL
                                {Customer_ID: this.value },
                              // The callback function. The results of the JSON call are passed into jData
                                function (jData) {
                                    var selectHtml = ""
                                    // Repopulate the project drop down with the results of the JSON call
                                    $.each(
                                        jData,
                                        function (jdIndex, jdData) {
                                            selectHtml = selectHtml + "<option value='" + jdData.Value + "'>" + jdData.Text + "</option>";
                                        });
                                    // dont use innerHTML as it is not supported properly by IE
                                    // insted use jQuery html to change the select list options
                                    $(eProject).html(selectHtml);
                                    // clear task list
                                    $(eTask).html(""); 
                                } // END getJSON callback function definition
                              ); // END getJSON function call
                          } // END change event definition
                      }] // END dataEvents definition
              } // END editoptions list
          }, // END Customer jqGrid field definition
            // Definition for Project drop down
              {name: 'Project', index: 'Project', width: 250, align: 'left', editable: true,
              edittype: "select", editoptions: { dataUrl: 'Timesheet/ProjectList'}
          }, // END Project jqGrid field definition
              {name: 'Task', index: 'Task', width: 250, align: 'left', editable: true, edittype: "select", editoptions: { dataUrl: 'Timesheet/TaskList'} },
              { name: 'Desc', index: 'Desc', width: 300, align: 'left', editable: true },
              { name: 'Hours', index: 'Hours', width: 50, align: 'left', editable: true },
              { name: 'Charge', index: 'Charge', edittype: 'checkbox', width: 18, align: 'center', editoptions: { value: "0:1" }, formatter: "checkbox", formatoptions: { disabled: false }, editable: true }
            ],
            //=============
            // Grid Events
            // when selecting, undo anything else
            onSelectRow: function (rowid, iRow, iCol, e) {
                if (rowid && rowid !== lastsel) {
                    // $(this).jqGrid('restoreRow', lastsel);
                    lastsel = rowid;
                }
            },
            // double click to edit
            ondblClickRow: function (rowid, iRow, iCol, e) {
                // browser independent stuff
                if (!e) e = window.event;
                var element = e.target || e.srcElement

                // When editing, change the drop down datasources to filter on the current parent
                // By default tasks are limited to the current project
                $(this).jqGrid('setColProp', 'Task', { editoptions: { dataUrl: 'Timesheet/TaskList?CustomerProject_ID=' + $(this).jqGrid('getCell', rowid, 'hProject_ID')} });

                // By default projects are limited to the current Customer (dataUrl)
                // Also attach event handler to autopopulate tasks (dataEvents)
                $(this).jqGrid('setColProp', 'Project', {
                    //                    editoptions: { dataUrl: 'Timesheet/ProjectList?Customer_ID=' + $(this).jqGrid('getCell', rowid, 'hCustomer_ID')} });
                    editoptions: {
                        dataUrl: 'Timesheet/ProjectList?Customer_ID=' + $(this).jqGrid('getCell', rowid, 'hCustomer_ID'),
                        dataEvents: [
                              {
                                  type: 'change',
                                  fn: function (e) {
                                      var eTask = '#' + $(this).attr("id").replace("_Project", "_Task");
                                      $.getJSON(
                                        'Timesheet/TaskListJSON',
                                        { CustomerProject_ID: this.value },
                                        function (jData) {
                                            var selectHtml = "";
                                            $.each(
                                                jData,
                                                function (jdIndex, jdData) {
                                                    selectHtml = selectHtml + "<option value='" + jdData.Value + "'>" + jdData.Text + "</option>";
                                                });
                                            $(eTask).html(selectHtml);
                                        } // END getJSON callback function definition
                                      ); // END getJSON function call
                                  } // END change event handler definition
                              }] // END dataevents definition
                    } // END editoptions list
                } // END data to be applied to setColProp
                ); // END jqGrid setColProp

                // Go into edit mode (automatically moves focus to first field)
                // Use setTimout to apply the focus and datepicker after the first field gets the focus
                $(this).jqGrid(
                    'editRow',
                    rowid,
                    {
                        keys: true,
                        oneditfunc: function (rowId) {
                            setTimeout(function () {
                                $("input, select", element).focus();
                                $("#" + rowId + "_tsdate").datepicker({ dateFormat: 'yy-mm-dd' });
                            }, 50);
                        }
                    }
                );

            },  // end ondblClickRow event handler
            postData:
                {
                    startDate: function () { return $('#startDate').val(); }
                }
        }); // END jQuery("#ts").jqGrid

        $("#ts").jqGrid('navGrid', '#pager', { view: false, edit: false, add: false, del: false, search: false });
        $("#ts").jqGrid('inlineNav', "#pager");

    });                                         // END jQuery(document).ready(function () {
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Nick.Mc
  • 18,304
  • 6
  • 61
  • 91
  • If you make some modification of the question or if you or somebody else write new answer I get no notification. So please write a short comment to my answer to notify my about new information. – Oleg Nov 13 '12 at 11:27

2 Answers2

2

I suppose that the reason of the problem which you have is the usage of jQuery.empty (see the lines eTask.empty(); and eProject.empty();). If you examine the description of jQuery.empty you will find the following:

To avoid memory leaks, jQuery removes other constructs such as data and event handlers from the child elements before removing the elements themselves.

If you want to remove elements without destroying their data or event handlers (so they can be re-added later), use .detach() instead.

It seems to me that in your case can can just construct the string which is concatenation of all <option> elements. Then you can use jQuery.html to replace all old options to the new one. You can not only solve your main problem, but have some performance advantage. The problem which you should understand, that if you change some element on the page web browser have to recalculate position or style of all existing elements on the page. So if you call jQuery.append in the loop then every call will follow at least to reflow which is expansive. So you should better write your program so that the number of changes on the page will be reduced. If you construct the innerHTML of the <select> elements first as HTML string and use one call of jQuery.html (or set just innerHTML property of the DOM element) you will have performance improvement.

Another problem which I see in your program is initializing of the selects from 'Project' and 'Task'. If the user start editing of the row the select elements will be filled with dataUrl: 'Timesheet/TaskList' and dataUrl: 'Timesheet/ProjectList'. So you will have all Project and Tasks and not only the Projects of the 'Customer' and the tasks based on the 'Customer' and 'Project' values. I think you will have to set row dependent initial values of dataUrl before the editing will be started. In case of form editing you could do this inside of onInitializeForm callback for example. If you use inline editing you should do the same before calling of editRow.

I recommend you to examine carefully the code of the demo from the answer. It uses no dataUrl but it change value property multiple times. Changing of value property will corresponds in your case the setting of dataUrl.

Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Excellent, thanks Oleg. It was really just a brute force attempt at getting it working. When I get home I'll take a look, but your answer is precisely why I ask questions on here -you went straight to a design issue that I never would have picked up. In my last question I posted the entire jqGrid definition, and shows the code (already suggested by yourself) that dynamically changes dataUrl when it goes into edit mode. So yes, currently when you go into edit mode the dataUrl has been pre-loaded with a prefiltered Url – Nick.Mc Nov 11 '12 at 23:21
  • Looking at your sample, if I understand correctly, all of the data is sitting in static jscript arrays. Do you think if I pre loaded the database drop down values into a jscript array, then did all the filtering client side, that it would work OK? – Nick.Mc Nov 11 '12 at 23:24
  • @ElectricLlama: The example don't do exactly what you mean, but is changes the value of `values` many times. I mentioned the demo only in the context that you didn't changed `dataUrl` value. In cases when I changed `values` you have to change the value of `dataUrl`. – Oleg Nov 11 '12 at 23:31
  • @ElectricLlama: I didn't found in what editing mode you use. If you look in my demo you will see that I had to distinguish 4 cases: inline editing, form editing, toolbar searching and advanced searching dialog (see the code of `changeStateSelect` function for example). So it's important to know in which situation you plan to use dependent selects. At least it would be important to know what editing mode you use currently in your test projects. – Oleg Nov 11 '12 at 23:39
  • Sorry, it's inline editing. I posted some abridged code in this question, but I will replace it with the full code when I get home for completeness. – Nick.Mc Nov 12 '12 at 00:32
  • PS do you have any comments on this bit of code which gets the dependent drop down? `var eProject = $('#' + $(this).attr("id").replace("_Customer", "_Project"));` It might be a little more portable if I use one of the javascript traversal functions to get the next drop down in the grid as opposed to explcitily naming 'Customer' and 'Project'. – Nick.Mc Nov 12 '12 at 00:43
  • OK I have reposted all the jqGrid code. I am using $().html to replace the option list and it does appear to improve performance. However I have removed the .empty() and the second drop down does not call it's change event. It's quite strange. If there is nothing obvious to you then I will try rearranging some code and see if it specific to the order of the drop downs or the name etc. – Nick.Mc Nov 12 '12 at 10:57
  • I have also edited the post to attempt to explain the issue more clearly. – Nick.Mc Nov 12 '12 at 11:08
  • I put a breakpoint in the working Customer drop down event and added `$(eProject), $(eTask) and $('#ts')` to the watches and inspected them. They certainly looked like jQuery objects but there was no sign of my handler code in any of them - I guess you can't inspect the handlers at runtime? Really I want to see if there is a handler attached to Customer but not one attached to Project. But I can't see one anywhere. – Nick.Mc Nov 12 '12 at 11:24
  • 1
    @ElectricLlama: I have to do my main job currently, so I'll examine your modified question later. Short tip for you: you can examine all event handles bound to an element using the following jQuery functions: `$("#theId").data("events")` for jQuery version < 1.8 and `$._data($("#theId")[0], "events");` for jQuery version >=1.8. You can place the expressions in Watch window of debugger. For example you can press F12 to start IE Developer Tools, choose "Script" and click "Start debugging". Then you can set breackponts on any place of JavaScript code and use "Watch" to display above expressions. – Oleg Nov 12 '12 at 11:52
  • Thanks Oleg, I will do that and get back to you - I don't expect you to decipher my code!!! – Nick.Mc Nov 12 '12 at 12:41
  • OK I've checked and `$._data($("#24333_Customer")[0], "events")` is an object. In it is `change: Array[1]`. However, `$._data($("#24333_Project")[0], "events")` is undefined. So now I am fairly certain that the event handler that I have defined in jqGrid against the Project drop down has not been attached. I don't know if this is due to a syntax error or a bug in jqGrid or some other event being fired and removing it. Tonight I will try rearranging and simplifying the events and see if that makes a difference. Thanks for your patience. I am going to keep a commentary here as I troubleshoot. – Nick.Mc Nov 13 '12 at 01:14
  • OLEG : I have accepted my answer because it is a specific answer to the question so in the interests of keeping the internet a 'good' place I mark mine as the answer. I hope you don't mind - we both know that you've have added loads of information for me. Please let me know if this is a problem. From answering other questions I know how frustrating it can be when you put in loads of time and effort and it is not appreciated. Like everyone here I appreciate it!!! – Nick.Mc Nov 14 '12 at 11:41
0

OK, the issue was that in the ondblClickRow event handler I was setting the editoptions / dataUrl property. As I was not also specifying the editoptions / dataEvents property at this point it was basically overwriting the static event handler with nothing.

in the ondblClickRow event handler I was only overwriting Project and Tasks drop down, which explains why the Project handler was being removed and not the Customer one.

Apologies to Oleg: I did not post the full code at the start, so I did not include the double click event.

Anyway Oleg if you can suggest how I can preserve the event handler I can award you the answer. Otherwise I will award this as the answer, even though your help has been invaluable. I'm guessing I might need to move the event handler definition down to the dblclick event handler rather than in the column definition?

Nick.Mc
  • 18,304
  • 6
  • 61
  • 91
  • I don't understand why you need call `setColProp` of inside of `ondblClickRow`. It seems to me that one need do *everything* inside of `editoptions.dataEvents.fn`. If you want you can set `dataUrl` inside of `ondblClickRow`, but setting of `dataEvents` is really not needed. If you look in [the demo](http://www.ok-soft-gmbh.com/jqGrid/EditWithDependendSelects2_.htm) which I referenced in my answer I set `editoptions.value` of dependent select inside of `change` handler and rebuild existing options. Exactly the same you can do but set `editoptions.dataUrl` instead of `editoptions.value`. – Oleg Nov 13 '12 at 11:15
  • 1
    You can set **initial** `dataUrl` which corresponds of selected row inside of `dataInit` (see the code of the same demo). You can get the rowid of selected row as `$(this).getGridParam('selrow')`. Alternatively you can **don't modify** `dataUrl` at all, but use `ajaxSelectOptions.data` with some properties like `CustomerProject_ID` defined *as function*. See [the answer](http://stackoverflow.com/a/8150307/315935) where you will need replace *inner* `data` to `CustomerProject_ID` – Oleg Nov 13 '12 at 11:20
  • I need to set `dataUrl` in `ondblClickRow` because otherwise it will use the default `dataUrl` set earlier, which is _every_ Project. This manifests itself as: when I go into edit mode, the Project drop down will have _every_ Project in it, not just that Customers Projects. However what I found was that when I set dataUrl and _not_ dataEvents in this event, it removes the default dataEvent change handler that I defined in the column definition. So this is my 'brute force' way of getting working. I can see in your demo that you've done things differently but I'm still working out how. – Nick.Mc Nov 14 '12 at 05:07
  • OK so if I use `dataInit` I can ensure that upon starting the edit, the drop down has the correct values. Then I can also use `dataEvents.change` to dynamically change it. And both of these can be set to functions that can call `getJson` to get the lists from the DB. Let me try that. – Nick.Mc Nov 14 '12 at 05:19
  • But wait: your column definition for _state_ has `editoptions: {value: states }`. Surely that is just every state? So when I first edit the row it should have _every_ state in it? But it doesn't - it knows the correct list. and it knows it _before_ I change the country, so I don't understand how it is defaulting to the correct list of states without changing country? – Nick.Mc Nov 14 '12 at 05:26
  • 1
    Look at `setStateValues` which will be called inside of `dataInit`. It sets `editoptions.value` and so *not every* state will be shown. I see additionally that you didn't understood the code from [the answer](http://stackoverflow.com/a/8150307/315935) which I described in my last comment. Options from `ajaxSelectOptions.data` will be **appended to URL** exactly like `postData` do this (see [the answer](http://stackoverflow.com/a/2928819/315935)). So the usage of `ajaxSelectOptions.data.CustomerProject_ID` is still recommended way. – Oleg Nov 14 '12 at 07:12
  • Thanks. I think you have the answers, I just can't yet comprehend them! Let me look further. – Nick.Mc Nov 14 '12 at 11:09
  • Aha, so that's how states are automatically filtered - they are called from dataInit in _Countries_. Thanks! With regards to ajaxSelectOptions, I'm going to have spend some more time reading. I can see it's a way to automatically attach URL parameter values to.. something... columns? But do they only get executed when you reload the entire grid? ANYWAY I think you have helped me more than enough and my original question is certainly answered. I will soldier on and ask another question when I have something more specific. THANKS – Nick.Mc Nov 14 '12 at 11:37
  • 1
    You are welcome! The `ajaxSelectOptions` is the option of jqGrid, but it will be used *not during filling of the grid*. It will be used only with `jQuery.ajax` calls made with `dataUrl`. So you can use `ajaxSelectOptions` to customize the Ajax request. If you use `ajaxSelectOptions: {data: {p: "val"}}` then `dataUrl` will be appended with `&p=val`. If you would use function instead of `"val"` then it will be called and the *results* returned by the function will be used as the value of parameter `p`. Nevertheless I think that you will need still much time to make all working. Best wishes! – Oleg Nov 14 '12 at 12:13