【问题标题】:Make cell readonly in Kendo Grid if condition is met如果满足条件,则在 Kendo Grid 中将单元格设为只读
【发布时间】:2014-01-19 19:32:56
【问题描述】:

假设我有这样的数据:

[
    {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<object>, "Value", "Name");

这里的问题是:如何使 ForeignKey 列可编辑,但只能在行中,其中 IsFkEnabled == true?编辑模式为 InCell。

【问题讨论】:

  • Kendo UI 不支持开箱即用,但您可以实现它,但干净/简单的实现取决于您使用的版本类型。是内联、弹出还是内嵌?

标签: javascript kendo-ui kendo-grid kendo-asp.net-mvc


【解决方案1】:

注意事项:

  • 此解决方案仅适用于单元格内编辑(内联或弹出式编辑 需要不同的方法)
  • 第一种方法可能会导致不需要的视觉效果(网格 跳跃)在某些情况下;如果你经历过,我 推荐方法#2
  • 如果您想使用 MVC 包装器,方法 #2 可能不起作用(尽管可以扩展 Kendo.Mvc.UI.Fluent.GridEventBuilder);在这种情况下,您需要在 JS 中绑定编辑处理程序

方法#1

使用网格的edit 事件,然后执行以下操作:

$("#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)

要通过 MVC 流式语法使用此功能,只需在匿名 edit 函数上方命名(例如 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
    }
}

并像这样引用它:

@(Html.Kendo().Grid()
    .Name("Grid")
    .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({
    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);

然后像#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();
        }
    }
});

这种方法的不同之处在于编辑器不会首先被创建(和聚焦)。 beforeEdit 方法使用与 #1 相同的 isEditable 方法。 见demo for this approach here

如果您想将此方法与 MVC 包装器一起使用,但不想/不能扩展 GridEventBuilder,您仍然可以在 JavaScript 中绑定您的事件处理程序(放置在网格 MVC 初始化程序下方):

$(function() {
    var grid = $("#grid").data("kendoGrid");
    grid.bind("beforeEdit", onEdit.bind(grid));
});

【讨论】:

  • Telerik,请立即实施方法 2!
  • 我想知道是否有人有如何实现这种 fo 内联编辑的示例?
  • @Azzi 这里有一个选项:stackoverflow.com/questions/24722893/…
  • 我在连接事件时遇到了问题(我正在使用 MVC 绑定创建网格)。最后,我只是在 editCell 实现中实现了我的整个事件处理程序。我的情况应该没问题,因为我只有页面上的网格。
  • 对,对于 MVC fluent 构建器,如果要使用 beforeEdit,您可能需要扩展 Kendo.Mvc.UI.Fluent.GridEventBuilder;我应该提到这一点
【解决方案2】:

这些方法都不适合我。一个非常简单的实现看起来像这样

edit: function (e) {
        e.container.find("input[name='Name']").each(function () { $(this).attr("disabled", "disabled") });       
    }

edit 是 kendo 网格声明的一部分,Name 是该字段的实际名称。

【讨论】:

    【解决方案3】:

    请尝试以下代码 sn-p。

    查看

    <script type="text/javascript">  
    
    function errorHandler(e) {  
        if (e.errors) {  
            var message = "Errors:\n";  
            $.each(e.errors, function (key, value) {  
                if ('errors' in value) {  
                    $.each(value.errors, function () {  
                        message += this + "\n";  
                    });  
                }  
            });  
            alert(message);  
        }  
    }  
    
    function onGridEdit(arg) {  
        if (arg.container.find("input[name=IsFkEnabled]").length > 0) {
            arg.container.find("input[name=IsFkEnabled]").click(function () {
                if ($(this).is(":checked") == false) {  
    
                }  
                else {  
                    arg.model.IsFkEnabled = true;
                    $("#Grid").data("kendoGrid").closeCell(arg.container);  
                    $("#Grid").data("kendoGrid").editCell(arg.container.next());  
                }  
            });  
        }  
        if (arg.container.find("input[name=FID]").length > 0) {  
            if (arg.model.IsFkEnabled == false) {
                $("#Grid").data("kendoGrid").closeCell(arg.container)  
            }  
        }  
    }  
    </script>  
    
    <div>
    @(Html.Kendo().Grid<MvcApplication1.Models.TestModels>()
        .Name("Grid")
        .Columns(columns =>
        {
            columns.Bound(p => p.ID);
            columns.Bound(p => p.Name);
            columns.Bound(p => p.IsFkEnabled);
            columns.ForeignKey(p => p.FID,   (System.Collections.IEnumerable)ViewData["TestList"], "Value", "Text");
    
        })
        .ToolBar(toolBar => toolBar.Save())
        .Editable(editable => editable.Mode(GridEditMode.InCell))
        .Pageable()
        .Sortable()
        .Scrollable()
        .Filterable()
        .Events(e => e.Edit("onGridEdit"))
        .DataSource(dataSource => dataSource
            .Ajax()
            .Batch(true)
            .ServerOperation(false)
            .Events(events => events.Error("errorHandler"))
            .Model(model =>
            {
                model.Id(p => p.ID);
                model.Field(p => p.ID).Editable(false);
            })
        .Read(read => read.Action("ForeignKeyColumn_Read", "Home"))
        .Update(update => update.Action("ForeignKeyColumn_Update", "Home"))
        )
    )
    </div>
    

    型号

    namespace MvcApplication1.Models
    {
        public class TestModels
        {
            public int ID { get; set; }
            public string Name { get; set; }
            public bool IsFkEnabled { get; set; }
            public int FID { get; set; }
        }
    }
    

    控制器

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
    
            List<SelectListItem> items = new List<SelectListItem>();
    
            for (int i = 1; i < 6; i++)
            {
                SelectListItem item = new SelectListItem();
                item.Text = "text" + i.ToString();
                item.Value = i.ToString();
                items.Add(item);
            }
    
            ViewData["TestList"] = items;
    
            return View();
        }
    
        public ActionResult ForeignKeyColumn_Read([DataSourceRequest] DataSourceRequest request)
        {
            List<TestModels> models = new List<TestModels>();
    
            for (int i = 1; i < 6; i++)
            {
                TestModels model = new TestModels();
                model.ID = i;
                model.Name = "Name" + i;
    
                if (i % 2 == 0)
                {
                    model.IsFkEnabled = true;
    
                }
    
                model.FID = i;
    
    
                models.Add(model);
            }
    
            return Json(models.ToDataSourceResult(request));
        }
    
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult ForeignKeyColumn_Update([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<TestModels> tests)
        {
            if (tests != null && ModelState.IsValid)
            {
                // Save/Update logic comes here  
            }
    
            return Json(ModelState.ToDataSourceResult());
        }
    }
    

    如果您想下载演示,请点击here

    【讨论】:

      【解决方案4】:

      最简单的方法是使用 dataBound 事件有条件地将特殊 CSS 类之一应用于网格忽略以进行编辑的单元格:

      • http://dojo.telerik.com/izOka

           dataBound: function(e) {
              var colIndex = 1;
        
              var rows = this.table.find("tr:not(.k-grouping-row)");
              for (var i = 0; i < rows.length; i++) {
                var row = rows[i];
                var model = this.dataItem(row);
        
                if (!model.Discontinued) {
                  var cell = $($(row).find("td")[colIndex]);
                  cell.addClass("k-group-cell");
                }
              }
        
            },
        

      【讨论】:

      • 如果您使用的是 2017 R2 之前的版本,该版本添加了官方的 BeforeEdit 事件,并且您使用的是 MVC 包装器(“Kendo MVC”),则此 hack 是解决问题的好方法。如果您使用它,我建议您在代码中添加注释,说明您为什么要劫持 k-group-cell 类,以便将来阅读您代码的人理解。
      【解决方案5】:

      另一种方法是使用您自己的“编辑器”函数进行列定义,根据您的条件提供输入元素或普通 div。

      【讨论】:

        【解决方案6】:

        使用模板列而不是绑定列

        columns.Template(@<text></text>).ClientTemplate("#=Id#").Title("Id");
        

        【讨论】:

          猜你喜欢
          • 2014-07-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-02-27
          相关资源
          最近更新 更多