如果条件满足,则在 Kendo Grid 中使单元格只读 [英] Make cell readonly in Kendo Grid if condition is met
问题描述
假设我有这样的数据:
<预><代码>[{ID: 1, SomeForeignKeyID: 4, IsFkEnabled: true},{ID: 2, SomeForeignKeyID: 9, IsFkEnabled: false}]Kendo Grid 正在使用这些数据:
columns.Bound(m => m.ID);columns.ForeignKey(p => p.SomeForeignKeyID, ViewBag.ForeignKeys as IEnumerable
这里的问题是:如何使 ForeignKey 列可编辑,但仅限于行,其中 IsFkEnabled == true?编辑模式为 InCell.
注意事项:
- 此解决方案仅适用于单元格内编辑(内联或弹出式编辑需要不同的方法)
- 第一种方法可能会导致不需要的视觉效果(网格跳跃)在某些情况下;如果你经历过,我推荐方法#2
- 如果您想使用 MVC 包装器,方法 #2 可能不起作用(尽管可以扩展 Kendo.Mvc.UI.Fluent.GridEventBuilder);在这种情况下,您需要在 JS 中绑定编辑处理程序
方法#1
使用网格的 edit 事件然后做像这样:
$("#grid").kendoGrid({数据源:数据源,高度:300px",列:列,可真实,功能(e){var fieldName = e.container.find("input").attr("name");//替代方案(如果您的可编辑文件中没有 name 属性)://var columnIndex = this.cellIndex(e.container);//var fieldName = this.thead.find("th").eq(columnIndex).data("field");if (!isEditable(fieldName, e.model)) {this.closeCell();//防止编辑}}});/*** @returns {boolean} 如果给定字段名的列是可编辑的,则为真*/功能是可编辑的(字段名称,模型){if (fieldName === "SomeForeignKeyID") {//字段SomeForeignKeyID"的条件//(如果定义的属性不存在,则默认为真)返回 model.hasOwnProperty("IsFkEnabled") &&模型.IsFkEnabled;}//额外的检查,例如只允许编辑未保存的行://if (!model.isNew()) { return false;}返回真;//默认为可编辑}
要通过 MVC 流畅的语法使用它,只需在名称上方给匿名 edit
函数(例如 onEdit
):
function onEdit(e) {var fieldName = e.container.find("input").attr("name");//替代方案(如果您的可编辑文件中没有 name 属性)://var columnIndex = this.cellIndex(e.container);//var fieldName = this.thead.find("th").eq(columnIndex).data("field");if (!isEditable(fieldName, e.model)) {this.closeCell();//防止编辑}}
并像这样引用它:
@(Html.Kendo().Grid().Name("网格").Events(events => events.Edit("onEdit")))
这样做的缺点是在触发编辑事件之前首先创建编辑器,这有时会产生不良的视觉效果.
方法#2
通过使用触发 beforeEdit
事件的变体覆盖其 editCell
方法来扩展网格;为了使用网格选项,您还需要覆盖 init 方法:
var oEditCell = kendo.ui.Grid.fn.editCell;var oInit = kendo.ui.Grid.fn.init;kendo.ui.Grid = kendo.ui.Grid.extend({初始化:函数(){oInit.apply(this, arguments);if (typeof this.options.beforeEdit === "function") {this.bind("beforeEdit", this.options.beforeEdit.bind(this));}},编辑单元格:函数(单元格){var that = this,单元格 = $(单元格),column = that.columns[that.cellIndex(cell)],模型 = that._modelForContainer(cell),事件 = {容器:细胞,型号:型号,字段:column.field};如果(模型&& this.trigger(beforeEdit",事件)){//如果在 beforeEdit 中被阻止,则不要编辑如果 (event.isDefaultPrevented()) 返回;}oEditCell.call(this, cell);}});kendo.ui.plugin(kendo.ui.Grid);
然后像#1一样使用它:
$("#grid").kendoGrid({数据源:数据源,高度:300px",列:列,可真实,beforeEdit: 函数(e) {var columnIndex = this.cellIndex(e.container);var fieldName = this.thead.find("th").eq(columnIndex).data("field");if (!isEditable(fieldName, e.model)) {e.preventDefault();}}});
这种方法的不同之处在于编辑器不会首先被创建(和聚焦).beforeEdit
方法使用与 #1 相同的 isEditable
方法.在此处查看此方法的演示.
如果您想将此方法与 MVC 包装器一起使用但不想/无法扩展 GridEventBuilder,您仍然可以在 JavaScript 中绑定您的事件处理程序(放置在网格 MVC 初始化程序下方):
$(function() {var grid = $("#grid").data("kendoGrid");grid.bind("beforeEdit", onEdit.bind(grid));});
Let's say I have a data like this:
[
{ID: 1, SomeForeignKeyID: 4, IsFkEnabled: true},
{ID: 2, SomeForeignKeyID: 9, IsFkEnabled: false}
]
Kendo Grid is using this data:
columns.Bound(m => m.ID);
columns.ForeignKey(p => p.SomeForeignKeyID, ViewBag.ForeignKeys as IEnumerable<object>, "Value", "Name");
Here's the problem: how to make ForeignKey column editable, but only in rows, where IsFkEnabled == true? Edit mode is InCell.
Notes:
- this solution works for in-cell editing only (inline or popup editing require a different approach)
- the first approach can lead to unwanted visual effects (grid jumping) under certain circumstances; if you experience that, I recommend approach #2
- approach #2 may not work if you want to use the MVC wrappers (although it may be possible to extend Kendo.Mvc.UI.Fluent.GridEventBuilder); in that case, you'll need to bind the edit handler in JS
Approach #1
Use the grid's edit event and then do something like this:
$("#grid").kendoGrid({
dataSource: dataSource,
height: "300px",
columns: columns,
editable: true,
edit: function (e) {
var fieldName = e.container.find("input").attr("name");
// alternative (if you don't have the name attribute in your editable):
// var columnIndex = this.cellIndex(e.container);
// var fieldName = this.thead.find("th").eq(columnIndex).data("field");
if (!isEditable(fieldName, e.model)) {
this.closeCell(); // prevent editing
}
}
});
/**
* @returns {boolean} True if the column with the given field name is editable
*/
function isEditable(fieldName, model) {
if (fieldName === "SomeForeignKeyID") {
// condition for the field "SomeForeignKeyID"
// (default to true if defining property doesn't exist)
return model.hasOwnProperty("IsFkEnabled") && model.IsFkEnabled;
}
// additional checks, e.g. to only allow editing unsaved rows:
// if (!model.isNew()) { return false; }
return true; // default to editable
}
Demo here (updated for Q1 2014)
To use this via the MVC fluent syntax, simply give the anonymous edit
function above a name (e.g. onEdit
):
function onEdit(e) {
var fieldName = e.container.find("input").attr("name");
// alternative (if you don't have the name attribute in your editable):
// var columnIndex = this.cellIndex(e.container);
// var fieldName = this.thead.find("th").eq(columnIndex).data("field");
if (!isEditable(fieldName, e.model)) {
this.closeCell(); // prevent editing
}
}
and reference it like this:
@(Html.Kendo().Grid()
.Name("Grid")
.Events(events => events.Edit("onEdit"))
)
The disadvantage to this is that the editor gets created first before the edit event is triggered, which can sometimes have undesirable visual effects.
Approach #2
Extend the grid by overriding its editCell
method with a variation that triggers a beforeEdit
event; for that to work with grid options, you'll also need to override the init method:
var oEditCell = kendo.ui.Grid.fn.editCell;
var oInit = kendo.ui.Grid.fn.init;
kendo.ui.Grid = kendo.ui.Grid.extend({
init: function () {
oInit.apply(this, arguments);
if (typeof this.options.beforeEdit === "function") {
this.bind("beforeEdit", this.options.beforeEdit.bind(this));
}
},
editCell: function (cell) {
var that = this,
cell = $(cell),
column = that.columns[that.cellIndex(cell)],
model = that._modelForContainer(cell),
event = {
container: cell,
model: model,
field: column.field
};
if (model && this.trigger("beforeEdit", event)) {
// don't edit if prevented in beforeEdit
if (event.isDefaultPrevented()) return;
}
oEditCell.call(this, cell);
}
});
kendo.ui.plugin(kendo.ui.Grid);
then use it similar to #1:
$("#grid").kendoGrid({
dataSource: dataSource,
height: "300px",
columns: columns,
editable: true,
beforeEdit: function(e) {
var columnIndex = this.cellIndex(e.container);
var fieldName = this.thead.find("th").eq(columnIndex).data("field");
if (!isEditable(fieldName, e.model)) {
e.preventDefault();
}
}
});
The difference of this approach is that the editor won't get created (and focused) first. The beforeEdit
method is using the same isEditable
method from #1.
See a demo for this approach here.
If you want to use this approach with MVC wrappers but don't want / can't extend GridEventBuilder, you can still bind your event handler in JavaScript (place below the grid MVC initializer):
$(function() {
var grid = $("#grid").data("kendoGrid");
grid.bind("beforeEdit", onEdit.bind(grid));
});
这篇关于如果条件满足,则在 Kendo Grid 中使单元格只读的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!