Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make cell readonly in Kendo Grid if condition is met

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.

like image 461
Andrzej Avatar asked Jan 02 '14 11:01

Andrzej


People also ask

How do I make my Kendo grid read only?

k-button and/or . k-button-icontext) to set readonly or disabled. The toolbutton works, but the in-row Edit and Delete buttons may not be changed (always clickable).

What is Databound event in kendo grid?

Fired when the widget is bound to data from its data source. The event handler function context (available via the this keyword) will be set to the widget instance.

What is selectable in kendo grid?

Description. There are situations when you would like to enable the end user to select rows or cells in the grid table, and process data from them or make calculations based on this selection. The Kendo UI grid supports selection by specifying its configuration via its selectable attribute.


1 Answers

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)); }); 
like image 156
Lars Höppner Avatar answered Sep 20 '22 11:09

Lars Höppner