New to Telerik UI for ASP.NET MVCStart a free 30-day trial

InCell Editing

InCell editing allows users to click Grid data cells and type new values like in Excel. There is no need for command buttons to enter and exit edit mode. Users can quickly move between the editable cells and rows by using keyboard navigation.

The InCell edit mode provides a different user experience, compared to the Inline and Popup edit modes. InCell edit mode can be more convenient for advanced users, fast users, or users who prefer keyboard navigation rather than clicking command buttons.

Read the Grid Editing Overview article first.

Basics

To enable the InCell Grid editing, set the Mode() option of the Editable() configuration to GridEditMode.InCell. During InCell editing, only one table cell is in edit mode at a time. Users can:

  • Click a specific cell to enter edit mode.
  • Press Tab or Shift + Tab to confirm the current value and edit the next or previous cell.
  • Press Enter to confirm the current value and exit edit mode when the Navigatable() option is enabled.
  • Press Esc to cancel the current change and exit edit mode when the Navigatable() option is enabled.
  • Click another cell to confirm the current value and edit the new cell.
  • Click outside the Grid to confirm the current value and exit edit mode.
  • Perform another Grid operation, for example, paging or sorting, to cancel the current edit operation.
  • Click the Add toolbar command to add a new row.
  • Click the Save changes toolbar command to submit any pending changes.
  • Click the Cancel changes toolbar command to cancel any pending changes.
  • Click the Delete command button to delete the respective row.

The non-editable cells do not enter edit mode.

Usually, the Batch() option of the DataSource is enabled when the Grid is set up for InCell editing. This way, the Create, Update, and Destroy requests are sent in batches. For example, updating two data items triggers a single Update request instead of two.

Commands

InCell add, edit, and delete operations use the following command buttons:

  • Add (toolbar command)
  • Delete (column command)
  • Save changes (toolbar command)—Activated when a new row is added, a row is deleted, or at least one cell is edited.
  • Cancel changes (column command)—Activated when the Grid contains a pending change.

In InCell edit mode, the Grid commands execute cell by cell, and the corresponding Grid client-side events also fire cell by cell.

Setting the InCell Edit Mode

The example below shows how to implement InCell Grid CRUD operations with the simplest and minimal required setup.

  1. Add a new class to the ~/Models folder, for example, ProductViewModel:

    C#
    using System.ComponentModel.DataAnnotations;
    
    public class ProductViewModel
    {
        // The unique model identifier field.
        public int ProductID { get; set; }
        [Required] // The ProductName property is required.
        public string ProductName { get; set; }
        public short? UnitsInStock { get; set; }
    }
  2. Open HomeController.cs and add a new action method that returns the dataset Products as JSON. The Grid makes Ajax requests to this action to read the data.

    C#
    public ActionResult Products_Read([DataSourceRequest]DataSourceRequest request)
    {
        // ToDataSourceResult works with IEnumerable and IQueryable.
        using (var northwind = new NorthwindEntities())
        {
            IQueryable<Product> products = northwind.Products;
            DataSourceResult result = products.ToDataSourceResult(request);
            return Json(result);
        }
    }
  3. Add a new action method to HomeController.cs, responsible for saving the new data items. Name the method Products_Create. Intercept the added data items as a collection of ProductViewModel, using the [Bind(Prefix="models")].

    C#
    public ActionResult Products_Create([DataSourceRequest]DataSourceRequest request, [Bind(Prefix="models")]IEnumerable<ProductViewModel> products)
    {
        // Will keep the inserted entities here. Used to return the result later.
        var entities = new List<Product>();
        if (ModelState.IsValid)
        {
            using (var northwind = new NorthwindEntities())
            {
                foreach (var product in products)
                {
                    // Create a new Product entity and set its properties from the posted ProductViewModel.
                    var entity = new Product
                    {
                        ProductName = product.ProductName,
                        UnitsInStock = product.UnitsInStock
                    };
                    // Add the entity.
                    northwind.Products.Add(entity);
                    // Store the entity for later use.
                    entities.Add(entity);
                }
                // Insert the entities in the database.
                northwind.SaveChanges();
            }
        }
        // Return the inserted entities. The Grid needs the generated ProductID. Also, return any validation errors through the ModelState.
        return Json(entities.ToDataSourceResult(request, ModelState, product => new ProductViewModel
        {
            ProductID = product.ProductID,
            ProductName = product.ProductName,
            UnitsInStock = product.UnitsInStock
        }));
    }
  4. Add an action method to HomeController.cs, responsible for saving the edited data items. Name the method Products_Update. Intercept the modified data items as a collection of ProductViewModel, using the [Bind(Prefix="models")].

    C#
    public ActionResult Products_Update([DataSourceRequest]DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<ProductViewModel> products)
    {
        // Will keep the updated entities here. Used to return the result later.
        var entities = new List<Product>();
        if (ModelState.IsValid)
        {
            using (var northwind = new NorthwindEntities())
            {
                foreach (var product in products)
                {
                    // Create a new Product entity and set its properties from the posted ProductViewModel.
                    var entity = new Product
                    {
                        ProductID = product.ProductID,
                        ProductName = product.ProductName,
                        UnitsInStock = product.UnitsInStock
                    };
                    // Store the entity for later use.
                    entities.Add(entity);
                    // Attach the entity.
                    northwind.Products.Attach(entity);
                    // Change its state to Modified so EntityFramework can update the existing product instead of creating a new one.
                    northwind.Entry(entity).State = EntityState.Modified;
                    // Or use ObjectStateManager if using a previous version of EntityFramework.
                    // northwind.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
                }
                // Update the entities in the database.
                northwind.SaveChanges();
            }
        }
        // Return the updated entities. Also, return any validation errors through the ModelState.
        return Json(entities.ToDataSourceResult(request, ModelState, product => new ProductViewModel
        {
            ProductID = product.ProductID,
            ProductName = product.ProductName,
            UnitsInStock = product.UnitsInStock
        }));
    }
  5. Add a new action method to HomeController.cs, responsible for saving the deleted data items. Name the method Products_Destroy. Intercept the removed data items as a collection of ProductViewModel, using the [Bind(Prefix="models")].

    C#
    public ActionResult Products_Destroy([DataSourceRequest]DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<ProductViewModel> products)
    {
        // Will keep the destroyed entities here. Used to return the result later.
        var entities = new List<Product>();
        if (ModelState.IsValid)
        {
            using (var northwind = new NorthwindEntities())
            {
                foreach (var product in products)
                {
                    // Create a new Product entity and set its properties from the posted ProductViewModel.
                    var entity = new Product
                    {
                        ProductID = product.ProductID,
                        ProductName = product.ProductName,
                        UnitsInStock = product.UnitsInStock
                    };
                    // Store the entity for later use.
                    entities.Add(entity);
                    // Attach the entity.
                    northwind.Products.Attach(entity);
                    // Delete the entity.
                    northwind.Products.Remove(entity);
                    // Or use DeleteObject if using a previous version of EntityFramework.
                    // northwind.Products.DeleteObject(entity);
                }
                // Delete the entity in the database.
                northwind.SaveChanges();
            }
        }
        // Return the destroyed entities. Also, return any validation errors through the ModelState.
        return Json(entities.ToDataSourceResult(request, ModelState, product => new ProductViewModel
        {
            ProductID = product.ProductID,
            ProductName = product.ProductName,
            UnitsInStock = product.UnitsInStock
        }));
    }
  6. Within the view, configure the Grid to use the action methods created in the previous steps. The Update and Destroy actions must return a collection with the modified or deleted records to enable the DataSource to apply the changes accordingly. The Create method must return a collection of the created records where each data item has an assigned ID field.

    Razor
    @(Html.Kendo().Grid<KendoGridBatchEditing.Models.ProductViewModel>()
        .Name("grid")
        .Columns(columns =>
        {
            columns.Bound(product => product.ProductID).Width(100);
            columns.Bound(product => product.ProductName);
            columns.Bound(product => product.UnitsInStock).Width(250);
            columns.Command(commands =>
            {
                commands.Destroy(); // The "destroy" command removes data items.
            }).Title("Commands").Width(200);
        })
        .ToolBar(toolbar =>
        {
            toolbar.Create(); // The "create" command adds new data items.
            toolbar.Save(); // The "save" command saves the changes.
        })
        .Editable(editable => editable.Mode(GridEditMode.InCell)) // Use InCell editing mode.
        .DataSource(dataSource => dataSource
            .Ajax()
            .Batch(true) // Enable batch updates.
            .Model(model =>
            {
                model.Id(product => product.ProductID); // Specify the property, which is the unique identifier of the model that binds to the Grid.
                model.Field(product => product.ProductID).Editable(false); // Make the "ProductID" property not editable.
            })
            .Create(create => create.Action("Products_Create", "Home")) // Action method invoked when the user saves new data items.
            .Read(read => read.Action("Products_Read", "Home"))  // Action method invoked when the Grid requests the data.
            .Update(update => update.Action("Products_Update", "Home"))  // Action method invoked when the user saves updated data items.
            .Destroy(destroy => destroy.Action("Products_Destroy", "Home")) // Action method invoked when the user removes data items.
        )
        .Pageable()
    )

Editors

By default, the Grid component serializes editors allocated within the ~/Views/Shared/EditorTemplates/ folder.

For example, the default editor of the string properties is the TextBox component, the CheckBox—for booleans, the DateTimePicker—for DateTime data type properties, and more.

C#
@model object 

@Html.Kendo().TextBoxFor(model => model)

If no editors are available in the ~/Views/Shared/EditorTemplates/ folder, the Grid will revert to using a default editor based on the primitive type.

To define a custom editor for a specified column:

  1. Add a view that contains the desired editor in the ~/Views/Shared/EditorTemplates/ folder:

    Razor
        <!-- ~/Views/Shared/EditorTemplates/CategoryEditor.cshtml-->
    
        @model int?
    
        @(Html.Kendo().DropDownListFor(m => m)
            .DataValueField("Id") // The value of the drop-down is taken from the "Id" property.
            .DataTextField("Name") // The text of the item is taken from the "Name" property.
            .BindTo((System.Collections.IEnumerable)ViewData["categories"]) // A list of all optipns, which is populated in the controller.
        )
  2. In the model class declaration, decorate the property with the UIHint data attribute and specify the name of the created view (CategoryEditor):

    C#
    public class ProductViewModel
    {
        public int ProductID { get; set; }
        [Required]
        public string ProductName { get; set; }
        public short? UnitsInStock { get; set; }
        [UIHint("CategoryEditor")]
        public int? CategoryID { get; set; }
    }

For a live example, visit the Custom Editing Demo of the Grid.

For more use-cases and information on the column editor templates, refer to the Editor Templates documentation.

See Also