Skip to content
Advertisement

jqGrid cascading drop down change event does not fire

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 () {

Advertisement

Answer

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?

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement