【问题标题】:jqGrid cascading drop down change event does not firejqGrid级联下拉更改事件不会触发
【发布时间】:2012-11-11 13:33:16
【问题描述】:

在 Oleg 和许多网站的帮助下,我一直致力于让级联数据绑定下拉菜单在 jqGrid 中发挥作用

我有三个下拉菜单:客户 > 项目 > 任务。更改客户应使用该客户项目重新加载项目。更改项目应使用该项目任务重新加载任务。

实际上,我已经通过在 Customer 中创建一个更改事件处理程序来让 Project 重新加载该 Customer 任务,该事件处理程序依次针对 URL 调用 getJson,然后用新选项替换 Project 下拉列表的内容。效果很好。

然后我将同样的逻辑应用到项目下拉列表中,但项目事件没有似乎触发了。在更改项目下拉列表时,我观察到以下情况:

  1. 任务下拉菜单没有改变
  2. Task Json 控制器事件没有被调用(它的意思是在项目更改事件中被getJSON 调用)
  3. 在 Firebug 的网络监视器中,不显示对 Task Json 控制器事件的​​调用和响应。
  4. 在 Firebug 中,它没有遇到我在项目更改事件处理程序中设置的断点

但是,Customer 事件处理程序运行良好,并且在我更改 Customer 时按预期执行上述所有 4 点。

我相当确定它不会针对项目下拉菜单触发更改事件。

如果我运行网页并编辑和更改项目下拉值作为我的第一个操作,它不会触发项目事件处理程序,因此我不认为这是重置项目事件处理程序的客户事件。

那么,有谁知道为什么我的客户更改事件被调用,但我的项目没有被调用?

有没有一种方法可以检查 DOM 或其他东西并查看我的事件是否已在运行时附加?是这样的吗?

我正在使用 jqGrid 4.4.1

我的 jqGrid 是这样设置的:

  • 使用内联编辑
  • 点击选择 dblclick 进行编辑
  • 日期选择器附加到日期列
  • 在编辑时,我从隐藏字段中获取了 select db 键值,但我希望可以将其删除。
  • 我有三个相邻的选择

这是我的 jqGrid 定义

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

此处的固定代码

我将更改事件处理程序定义从列定义中移到了 dblclick 事件处理程序中。它仍然不完美。我确信每次附加事件处理程序都会产生一些开销,并且当客户更改时,它会更新并选择第一个项目但会清除任务。

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

【问题讨论】:

  • 如果您对问题进行了一些修改,或者您或其他人写了新的答案,我不会收到任何通知。因此,请在我的回答中写一个简短的评论,以通知我有关新信息的信息。

标签: javascript jquery jqgrid jquery-events jqgrid-asp.net


【解决方案1】:

我想您遇到问题的原因是使用了jQuery.empty(参见eTask.empty();eProject.empty(); 行)。如果您检查jQuery.empty 的描述,您会发现以下内容:

为避免内存泄漏,jQuery 移除了其他构造,例如数据 和子元素中的事件处理程序,然后再删除 元素本身。

如果您想删除元素而不破坏其数据或事件 处理程序(以便以后可以重新添加),请改用 .detach()。

在我看来,在您的情况下,可以只构造所有&lt;option&gt; 元素串联的字符串。然后您可以使用jQuery.html 将所有旧选项替换为新选项。您不仅可以解决您的主要问题,而且还具有一些性能优势。您应该了解的问题是,如果您更改页面上的某些元素,Web 浏览器必须重新计算 页面上所有现有元素的位置或样式。因此,如果您在循环中调用jQuery.append,那么每个调用都将至少跟随reflow,这是扩展的。所以你应该更好地编写你的程序,这样页面上的更改次数就会减少。如果您首先将&lt;select&gt; 元素的innerHTML 构造为HTML 字符串并使用jQuery.html一次调用(或仅设置DOM 元素的innerHTML 属性),您将获得性能提升.

我在您的程序中看到的另一个问题是初始化“项目”和“任务”中的选择。如果用户开始编辑行,则选择元素将填充dataUrl: 'Timesheet/TaskList'dataUrl: 'Timesheet/ProjectList'。因此,您将拥有所有项目和任务,而不仅仅是'Customer' 的项目和基于'Customer''Project' 值的任务。我认为您必须在开始编辑之前设置 dataUrl 的行相关初始值。例如,在表单编辑的情况下,您可以在 onInitializeForm 回调中执行此操作。如果您使用内联编辑,您应该在调用editRow 之前执行相同的操作

我建议你仔细检查the answer 中的the demo 的代码。它不使用dataUrl,但它多次更改value 属性。在您的情况下,value 属性的更改将对应于 dataUrl 的设置。

【讨论】:

  • 太好了,谢谢奥列格。这实际上只是让它发挥作用的蛮力尝试。当我回到家时,我会看看,但你的回答正是我在这里提问的原因——你直接谈到了一个我永远不会回答的设计问题。在我的最后一个问题中,我发布了整个 jqGrid 定义,并显示了在进入编辑模式时动态更改 dataUrl 的代码(已经由您自己建议)。所以是的,目前当您进入编辑模式时,dataUrl 已经预加载了预过滤的 Url
  • 查看您的示例,如果我理解正确,所有数据都位于静态 jscript 数组中。你认为如果我将数据库下拉值预加载到一个 jscript 数组中,然后所有过滤客户端都做了,它会正常工作吗?
  • @ElectricLlama:该示例并没有完全按照您的意思进行,而是多次更改了values 的值。我仅在您没有更改 dataUrl 值的情况下提到了演示。如果我更改了values,您必须更改dataUrl 的值。
  • @ElectricLlama:我没有找到您使用的编辑模式。如果您查看我的演示,您会发现我必须区分 4 种情况:内联编辑、表单编辑、工具栏搜索和高级搜索对话框(例如,参见 changeStateSelect 函数的代码)。因此,了解您计划在哪种情况下使用依赖选择非常重要。至少了解您当前在测试项目中使用的编辑模式很重要。
  • @ElectricLlama:我现在要做我的主要工作,所以稍后我会检查你修改后的问题。给您的简短提示:您可以使用以下 jQuery 函数检查绑定到元素的所有事件句柄:$("#theId").data("events") 用于 jQuery 版本 $._data($("#theId")[0], "events"); 用于 jQuery 版本 >=1.8。您可以将表达式放在调试器的 Watch 窗口中。例如,您可以按 F12 启动 IE Developer Tools,选择“脚本”并单击“开始调试”。然后你可以在 JavaScript 代码的任何地方设置 breackponts 并使用“Watch”来显示上面的表达式。
【解决方案2】:

好的,问题在于我在 ondblClickRow 事件处理程序中设置了 editoptions / dataUrl 属性。由于此时我还没有指定 editoptions / dataEvents 属性,它基本上是什么都没有覆盖静态事件处理程序。

在 ondblClickRow 事件处理程序中,我只覆盖了 Project 和 Tasks 下拉菜单,这解释了为什么要删除 Project 处理程序而不是 Customer 处理程序。

向 Oleg 道歉:我一开始没有发布完整的代码,所以我没有包含双击事件。

无论如何,Oleg 如果您能建议我如何保留事件处理程序,我可以为您提供答案。否则,即使您的帮助非常宝贵,我也会将此作为答案。我猜我可能需要将事件处理程序定义向下移动到 dblclick 事件处理程序而不是列定义中?

【讨论】:

  • 我不明白您为什么需要在ondblClickRow 内部调用setColProp。在我看来,需要在editoptions.dataEvents.fn 内做所有事情。如果您愿意,您可以在ondblClickRow 中设置dataUrl,但实际上不需要设置dataEvents。如果您查看我在回答中引用的the demo,我在change 处理程序中设置了依赖选择的editoptions.value 并重建现有选项。你可以做的完全一样,但是设置editoptions.dataUrl而不是editoptions.value
  • 您可以设置 initial dataUrl 对应于dataInit 内的选定行(参见同一演示的代码)。您可以将所选行的 rowid 获取为$(this).getGridParam('selrow')。或者,您可以完全不修改 dataUrl,而是使用ajaxSelectOptions.data 和一些属性,如将CustomerProject_ID 定义为作为函数。请参阅the answer,您需要将 inner data 替换为 CustomerProject_ID
  • 我需要在ondblClickRow中设置dataUrl,否则它将使用之前设置的默认dataUrl,即每个项目。这表现为:当我进入编辑模式时,项目下拉列表将包含 每个 项目,而不仅仅是客户项目。但是我发现,当我在此事件中设置 dataUrl 和 not dataEvents 时,它会删除我在列定义中定义的默认 dataEvent 更改处理程序。所以这是我开始工作的“蛮力”方式。我可以在您的演示中看到您的做法有所不同,但我仍在研究如何做。
  • 查看setStateValues,它将在dataInit 内部调用。它设置了editoptions.value,所以不是每个状态都会显示。我还看到您不理解我在上一条评论中描述的the answer 的代码。 ajaxSelectOptions.data 中的选项将被附加到 URL,就像 postData 一样(参见 the answer)。所以还是推荐使用ajaxSelectOptions.data.CustomerProject_ID
  • 不客气! ajaxSelectOptions 是 jqGrid 的选项,但它不会在填充网格时使用。它将仅用于使用dataUrl 进行的jQuery.ajax 调用。所以您可以使用ajaxSelectOptions 来自定义Ajax 请求。如果您使用ajaxSelectOptions: {data: {p: "val"}},那么dataUrl 将附加&amp;p=val。如果您使用函数而不是"val",那么它将被调用,并且函数返回的results 将用作参数p 的值。尽管如此,我认为您仍需要很多时间才能使所有工作正常进行。最美好的祝愿!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-21
  • 1970-01-01
  • 2017-06-19
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
相关资源
最近更新 更多