如何使 jqGrid 根据行数据动态填充选项列表
How to make jqGrid dynamically populate options list based on row data
我正在使用带有内联编辑功能的 jQrid 3.8.1 版,并且网格中的每一行都有几个要填充的下拉列表。当用户编辑该行时,我需要执行 AJAX 查询以获取每个列表的值。我已经看到 this post 关于如何做到这一点。 dataUrl
和 buildSelect
特征似乎是这里的标准答案。不过有几个问题我想不通:
用户正在编辑的行有一个值必须传递到 dataUrl
值中。例如,假设每行包含一个名为 "SpecialValue" 的字段,第 1 行的字段 SpecialValue = 100。第 1 行的 dataUrl
字段将为“http://my.services.com?SpecialValue=100”。我该怎么做?
网格中的每一行大约有 10 个 select 个框需要填充。出于效率原因,我不想进行 10 个单独的 AJAX 调用。最好是一次调用以获取所有数据,将其拆分并相应地填充每个 select 框。那可能吗?我尝试在 onSelectRow
中执行此操作,但网格最终忽略了我放入其中的值(我猜想对编辑行时触发的事件进行排序)。
编辑:
在阅读了 Oleg 的回答并进一步研究之后,我很清楚使用 dataUrl
和 buildSelect
对我来说效果不佳。我正在使用的 jqGrid 版本不支持按我需要的方式使用 dataUrl
。即使是这样,我也不想为每个下拉列表发送多个单独的请求。
我决定在 gridComplete
触发时执行一个请求,将所有下拉列表所需的所有数据提取到一个 JSON 结构中。然后当用户 select 一行进行内联编辑时,我将从该 JSON 结构填充行中的每个列表(下面的代码使用 getSelectValuesFromJSON() 函数 - -我没有给出它的定义,但你可以想象它通过结构查看并获得适当的值列表,但在列表框中)。
我有几个候选解决方案,但我对其中任何一个都不是 100% 满意。
解决方案 1:
在 onSelectRow
中,我调用 editRow
覆盖 on oneditfunc
以从我需要的网格中获取数据。假设需要 Field1
中的值来获取要放入 Field2
中列表的值。
onSelectRow: function (index, status, e) {
jQuery('#my_grid').jqGrid('editRow', index, true, function(rowId) {
var f1Val = $('#my_grid').jqGrid('getCell', index, 'Field1');
var selectVals = getSelectValuesFromJSON(f1Val); //gets data out of previously loaded JSON structure
var select = $('#my_grid').find('tr[id="' + index + '"] td[aria-describedby="my_grid_Field2"] select');
_.each(selectVals, function(selectVal) {
$(select).append($("<option></option>").attr("value", selectVal).text(selectVal));
});
});
}
这可行,但我对这条线犹豫不决
var select = $('#my_grid').find('tr[id="' + index + '"] td[aria-describedby="my_grid_Field2"] select');
依赖于这个我不太了解的aria-describedby
属性。看起来又老又脆。
解决方案 2:
当用户 select 一行时,利用 beforeSelectRow
动态更改 Field2 列的模型。
beforeSelectRow: function(index, e) {
var f1Val = getGridCellValue('#my_grid', index, 'Field1');
var values = getSelectValuesFromJSON(f1Val); //gets data out of previously loaded JSON structure
var valStr = "";
_.each(values, function(value) {
valStr += value + ":" + value + ";"
});
jQuery('#grid_pipes').setColProp('Field2', { editoptions: { value: valStr } });
return true;
}
这也行,但我不确定这是否真的是个好主意。这样动态更改列的模型是否有效?如果用户同时编辑多行 select 怎么办?一个列不是只有一个模型吗?那是什么意思?
为了回答 Oleg 的一些问题,dataType
已设置为使用 $.ajax 到 post 数据到服务器的函数。我想我读到这不再是推荐的方法。我继承了这段代码,所以我不确定为什么这样做,但除非有真正令人信服的理由,否则它可能不会改变。
未指定 loadonce
布尔值,所以我想这意味着它默认为 false
。
这是列模型的简化版本(没有什么特别之处):
colModel: [
{ name: 'PK', index: 'PK', hidden: true, editable: true, sortable: true, search: true },
{ name: 'Field1', index: 'Field1', hidden: true, editable: true, sortable: true, search: true },
{ name: 'Field2', index: 'Field2', sortable: false, editable: true, search: false, edittype: "select", editoptions: {} },
{ name: 'Field3', index: 'Field3', sortable: false, editable: true, search: false, edittype: "select", editoptions: {} },
...
]
你没有写你目前使用的是哪个版本的jqGrid,但是dataUrl
可以定义为带有(rowid, value, name)
参数的回调函数,它必须return URL 您可以根据信息动态构建。该功能从 v4.5.3 开始存在(参见 the line)。您可以在回调中使用 getCell
、getRowData
或 getLocalRow
从该行的其他列获取数据。因此你可以相对容易地解决你的第一个问题。
在我看来,你的第二个问题完全独立于第一个问题。最好将此类问题分开放在不同的 post 中,以便搜索引擎更好地索引信息,从而帮助其他人找到它。
没有解决第二个问题的简单方法,但肯定可以提出一种解决方案,但必须了解更多详细信息你做了什么以及你是怎么做的。您如何开始内联编辑(您是使用 inlineNav
、formatter: "actions"
还是直接调用 editRow
)?您使用哪个版本的 jqGrid(直到 4.7 版),free jqGrid or Guriddo jqGrid JS? select的列是如何在colModel
中定义的?您使用哪个 datatype
以及是否使用 loadonce: true
?我建议您 post 将问题与信息分开 。
更新: 如果你必须使用旧版本的 jqGrid 那么你不能动态生成 dataUrl
,但是因为你只需要添加 SpecialValue=100"
部分到 URL 你可以遵循我在许多旧答案中描述的技巧(第一个可能是 here,但是询问用户的 属性 名称的选择可以被误解)。您可以使用 ajaxSelectOptions.data
来定义 jQuery.ajax 请求的 data
参数。唯一的问题是您只能定义 一个 ajaxSelectOptions.data
属性。所以你可以添加下面的jqGrid选项:
ajaxSelectOptions: {
data: {
SpecialValue: function () {
var rowid = $myGrid.jqGrid("getGridParam", "selrow");
return $myGrid.jqGrid("getCell", rowid, "SpecialValue");
}
}
}
($myGrid
类似于 $("#grid")
)
更新: 您在问题的更新部分使用了未知函数 getSelectValuesFromJSON
、getLookupValuesFromJSON
。两者似乎都使用 synchronous Ajax 请求,这并不好。此外,您将 editoptions.value
设置为 只有一个 Field2
而不是设置 all selects.
onSelectRow: function (rowid) {
var $myGrid = $(this);
$.ajax({
url: "someUrl",
dataType: "json";
data: {
specialValue: $myGrid.jqGrid("getCell", rowid, "Field1")
},
success: function (data) {
// for example response data have format:
// { "Field2": ["v1", "v2", ...], "Field3": ["v3", "v4", ...] }
var filed, str;
for (filed in data) {
if (data.hasOwnProperty(filed)) {
str = $.map(data[filed], function (item) {
return item + ":" + item
}).join(";");
$myGrid.jqGrid("setColProp", filed, {
editoptions: {
value: str
}
});
}
}
$myGrid.jqGrid("editRow", rowid, true);
}
});
}
不过,"Solution 2" 更接近我向您推荐的内容。使用 onSelectRow
还是 beforeSelectRow
并不重要。您可以向服务器发出 异步 Ajax 请求 returns 信息 all select需要。 从服务器(在 success
回调内部)获得响应 后,您可以为所有 select 设置 editoptions.value
,然后才可以开始editRow
。在这种情况下,您将确保编辑该行将使用所有 select.
中的行特定选项
一些补充说明。我建议您验证网格中的 gridview: true
选项。此外,我怀疑您以不完全正确的方式填充网格,因为您隐藏了 PK
列并且您使用 index
而不是 rowid
作为 beforeSelectRow
和 onSelectRow
。了解当前 jqGrid 的实现总是在网格 的每一行(<tr>
元素)上分配 id
属性非常重要。因此,您 必须 在每个输入数据项中提供 id
信息。如果你想 向用户显示 id 信息(因此在 colModel
中有列与主键)那么你应该只包括 key: true
属性 在列定义中。例如,您可以将 key: true
添加到 PK
列的定义中,因此您将拥有 rowid
(或 index
在您的情况下)具有与 [=40= 相同的值].它简化了代码的许多部分。例如 jqGrid 在编辑请求中向服务器发送 id
参数。在请求中包含 PK
是实用的。此外,如果您使用 jsonReader
的 repeatitems: false
格式,您可以在 jsonReader
中包含 id: "PK"
而不是隐藏 PK
列。它通知 jqGrid 从 PK
获取 rowid。 jqGrid 会将 PK
保存在 <tr>
的 id
属性中,并且您不需要在网格中添加具有相同信息的其他 <td style="display:none">
。
最后一句话。我强烈建议您将复古版本 jqGrid 3.8.1 更新到更新的版本,例如 free jqGrid. Even if you would use no features (like Font Awesome)您将拥有性能优势,以及 现代网络浏览器的外观 看起来会好很多。你应该明白 jqGrid 3.8.1 是用旧的(和慢 jQuery 1.4.2)测试的。与Internet Explorer 8一起使用的版本作为最新的IE版本(IE9于2011年3月晚些时候发布)并且更面向IE6/IE7。现代 Chrome/Firefox/Safari 的外观可能很糟糕。是你想要的吗?
我正在使用带有内联编辑功能的 jQrid 3.8.1 版,并且网格中的每一行都有几个要填充的下拉列表。当用户编辑该行时,我需要执行 AJAX 查询以获取每个列表的值。我已经看到 this post 关于如何做到这一点。 dataUrl
和 buildSelect
特征似乎是这里的标准答案。不过有几个问题我想不通:
用户正在编辑的行有一个值必须传递到
dataUrl
值中。例如,假设每行包含一个名为 "SpecialValue" 的字段,第 1 行的字段 SpecialValue = 100。第 1 行的dataUrl
字段将为“http://my.services.com?SpecialValue=100”。我该怎么做?网格中的每一行大约有 10 个 select 个框需要填充。出于效率原因,我不想进行 10 个单独的 AJAX 调用。最好是一次调用以获取所有数据,将其拆分并相应地填充每个 select 框。那可能吗?我尝试在
onSelectRow
中执行此操作,但网格最终忽略了我放入其中的值(我猜想对编辑行时触发的事件进行排序)。
编辑:
在阅读了 Oleg 的回答并进一步研究之后,我很清楚使用 dataUrl
和 buildSelect
对我来说效果不佳。我正在使用的 jqGrid 版本不支持按我需要的方式使用 dataUrl
。即使是这样,我也不想为每个下拉列表发送多个单独的请求。
我决定在 gridComplete
触发时执行一个请求,将所有下拉列表所需的所有数据提取到一个 JSON 结构中。然后当用户 select 一行进行内联编辑时,我将从该 JSON 结构填充行中的每个列表(下面的代码使用 getSelectValuesFromJSON() 函数 - -我没有给出它的定义,但你可以想象它通过结构查看并获得适当的值列表,但在列表框中)。
我有几个候选解决方案,但我对其中任何一个都不是 100% 满意。
解决方案 1:
在 onSelectRow
中,我调用 editRow
覆盖 on oneditfunc
以从我需要的网格中获取数据。假设需要 Field1
中的值来获取要放入 Field2
中列表的值。
onSelectRow: function (index, status, e) {
jQuery('#my_grid').jqGrid('editRow', index, true, function(rowId) {
var f1Val = $('#my_grid').jqGrid('getCell', index, 'Field1');
var selectVals = getSelectValuesFromJSON(f1Val); //gets data out of previously loaded JSON structure
var select = $('#my_grid').find('tr[id="' + index + '"] td[aria-describedby="my_grid_Field2"] select');
_.each(selectVals, function(selectVal) {
$(select).append($("<option></option>").attr("value", selectVal).text(selectVal));
});
});
}
这可行,但我对这条线犹豫不决
var select = $('#my_grid').find('tr[id="' + index + '"] td[aria-describedby="my_grid_Field2"] select');
依赖于这个我不太了解的aria-describedby
属性。看起来又老又脆。
解决方案 2:
当用户 select 一行时,利用 beforeSelectRow
动态更改 Field2 列的模型。
beforeSelectRow: function(index, e) {
var f1Val = getGridCellValue('#my_grid', index, 'Field1');
var values = getSelectValuesFromJSON(f1Val); //gets data out of previously loaded JSON structure
var valStr = "";
_.each(values, function(value) {
valStr += value + ":" + value + ";"
});
jQuery('#grid_pipes').setColProp('Field2', { editoptions: { value: valStr } });
return true;
}
这也行,但我不确定这是否真的是个好主意。这样动态更改列的模型是否有效?如果用户同时编辑多行 select 怎么办?一个列不是只有一个模型吗?那是什么意思?
为了回答 Oleg 的一些问题,dataType
已设置为使用 $.ajax 到 post 数据到服务器的函数。我想我读到这不再是推荐的方法。我继承了这段代码,所以我不确定为什么这样做,但除非有真正令人信服的理由,否则它可能不会改变。
未指定 loadonce
布尔值,所以我想这意味着它默认为 false
。
这是列模型的简化版本(没有什么特别之处):
colModel: [
{ name: 'PK', index: 'PK', hidden: true, editable: true, sortable: true, search: true },
{ name: 'Field1', index: 'Field1', hidden: true, editable: true, sortable: true, search: true },
{ name: 'Field2', index: 'Field2', sortable: false, editable: true, search: false, edittype: "select", editoptions: {} },
{ name: 'Field3', index: 'Field3', sortable: false, editable: true, search: false, edittype: "select", editoptions: {} },
...
]
你没有写你目前使用的是哪个版本的jqGrid,但是dataUrl
可以定义为带有(rowid, value, name)
参数的回调函数,它必须return URL 您可以根据信息动态构建。该功能从 v4.5.3 开始存在(参见 the line)。您可以在回调中使用 getCell
、getRowData
或 getLocalRow
从该行的其他列获取数据。因此你可以相对容易地解决你的第一个问题。
在我看来,你的第二个问题完全独立于第一个问题。最好将此类问题分开放在不同的 post 中,以便搜索引擎更好地索引信息,从而帮助其他人找到它。
没有解决第二个问题的简单方法,但肯定可以提出一种解决方案,但必须了解更多详细信息你做了什么以及你是怎么做的。您如何开始内联编辑(您是使用 inlineNav
、formatter: "actions"
还是直接调用 editRow
)?您使用哪个版本的 jqGrid(直到 4.7 版),free jqGrid or Guriddo jqGrid JS? select的列是如何在colModel
中定义的?您使用哪个 datatype
以及是否使用 loadonce: true
?我建议您 post 将问题与信息分开 。
更新: 如果你必须使用旧版本的 jqGrid 那么你不能动态生成 dataUrl
,但是因为你只需要添加 SpecialValue=100"
部分到 URL 你可以遵循我在许多旧答案中描述的技巧(第一个可能是 here,但是询问用户的 属性 名称的选择可以被误解)。您可以使用 ajaxSelectOptions.data
来定义 jQuery.ajax 请求的 data
参数。唯一的问题是您只能定义 一个 ajaxSelectOptions.data
属性。所以你可以添加下面的jqGrid选项:
ajaxSelectOptions: {
data: {
SpecialValue: function () {
var rowid = $myGrid.jqGrid("getGridParam", "selrow");
return $myGrid.jqGrid("getCell", rowid, "SpecialValue");
}
}
}
($myGrid
类似于 $("#grid")
)
更新: 您在问题的更新部分使用了未知函数 getSelectValuesFromJSON
、getLookupValuesFromJSON
。两者似乎都使用 synchronous Ajax 请求,这并不好。此外,您将 editoptions.value
设置为 只有一个 Field2
而不是设置 all selects.
onSelectRow: function (rowid) {
var $myGrid = $(this);
$.ajax({
url: "someUrl",
dataType: "json";
data: {
specialValue: $myGrid.jqGrid("getCell", rowid, "Field1")
},
success: function (data) {
// for example response data have format:
// { "Field2": ["v1", "v2", ...], "Field3": ["v3", "v4", ...] }
var filed, str;
for (filed in data) {
if (data.hasOwnProperty(filed)) {
str = $.map(data[filed], function (item) {
return item + ":" + item
}).join(";");
$myGrid.jqGrid("setColProp", filed, {
editoptions: {
value: str
}
});
}
}
$myGrid.jqGrid("editRow", rowid, true);
}
});
}
不过,"Solution 2" 更接近我向您推荐的内容。使用 onSelectRow
还是 beforeSelectRow
并不重要。您可以向服务器发出 异步 Ajax 请求 returns 信息 all select需要。 从服务器(在 success
回调内部)获得响应 后,您可以为所有 select 设置 editoptions.value
,然后才可以开始editRow
。在这种情况下,您将确保编辑该行将使用所有 select.
一些补充说明。我建议您验证网格中的 gridview: true
选项。此外,我怀疑您以不完全正确的方式填充网格,因为您隐藏了 PK
列并且您使用 index
而不是 rowid
作为 beforeSelectRow
和 onSelectRow
。了解当前 jqGrid 的实现总是在网格 的每一行(<tr>
元素)上分配 id
属性非常重要。因此,您 必须 在每个输入数据项中提供 id
信息。如果你想 向用户显示 id 信息(因此在 colModel
中有列与主键)那么你应该只包括 key: true
属性 在列定义中。例如,您可以将 key: true
添加到 PK
列的定义中,因此您将拥有 rowid
(或 index
在您的情况下)具有与 [=40= 相同的值].它简化了代码的许多部分。例如 jqGrid 在编辑请求中向服务器发送 id
参数。在请求中包含 PK
是实用的。此外,如果您使用 jsonReader
的 repeatitems: false
格式,您可以在 jsonReader
中包含 id: "PK"
而不是隐藏 PK
列。它通知 jqGrid 从 PK
获取 rowid。 jqGrid 会将 PK
保存在 <tr>
的 id
属性中,并且您不需要在网格中添加具有相同信息的其他 <td style="display:none">
。
最后一句话。我强烈建议您将复古版本 jqGrid 3.8.1 更新到更新的版本,例如 free jqGrid. Even if you would use no features (like Font Awesome)您将拥有性能优势,以及 现代网络浏览器的外观 看起来会好很多。你应该明白 jqGrid 3.8.1 是用旧的(和慢 jQuery 1.4.2)测试的。与Internet Explorer 8一起使用的版本作为最新的IE版本(IE9于2011年3月晚些时候发布)并且更面向IE6/IE7。现代 Chrome/Firefox/Safari 的外观可能很糟糕。是你想要的吗?