Search code examples
asp.net-mvc-5kendo-gridkendo-asp.net-mvcmvc-editor-templates

Binding an editor template for Kendo grid


I am having difficulties in wiring up a custom EditorTemplate to a grid within an MVC 5 application. I have an integer field that only accepts a 1 or 2 as a value. Rather than using a standard numeric text box or slider control, I'd like to wire this up using buttons (via Bootstrap's group buttons). If the user clicks on the first button, the value should be set to 1, otherwise it should be set to 2.

The problem that I'm experiencing is that when the user clicks on the "edit" button, the "Level" value never gets applied to the editor template. The template displays as I'd like, but I cannot figure out how to bind the selected value back to the Kendo grid. When the user clicks on the "save" button on the grid, the controller action is never invoked.

If I replace the editor template with a standard Kendo control such as a numeric text box or Kendo slider, it works fine.

ViewModel

public class LotViewModel
{
   public int LotId { get; set; }
   [Display(Name = "Level")]
   [Range(1, 2)]
   [UIHint("LotLevel")]
   public int Level { get; set; }
}

View

@(Html.Kendo().Grid<LotViewModel>()
  .Name("lotGrid")
  .Columns(columns =>
  {
    columns.Bound(x => x.LotId).Visible(false);
    columns.Bound(x => x.Level);
    columns.Command(command =>
    {
      command.Edit();
    }).Width(100);
  })
  .ToolBar(toolbar => toolbar.Create())
  .Editable(editable => editable.Mode(GridEditMode.InLine))
  .AutoBind(true)
  .DataSource(dataSource => dataSource
    .Ajax()
    .Model(model =>
    {
      model.Id(m => m.LotId);
      model.Field(m => m.Level).DefaultValue(1);
    })
    .Read(update => update.Action("GetLots", "Lot"))
    .Create(update => update.Action("CreateLot", "Lot"))
    .Update(update => update.Action("UpdateLot", "Lot"))
  )
  )

EditorTemplate: LotLevel

@model int
@{
   var levelOne = Model.Equals(1) ? "active btn-primary" : null;
   var levelTwo = Model.Equals(2) ? "active btn-primary" : null;

   var htmlField = ViewData.TemplateInfo.HtmlFieldPrefix;
 }

@Html.HiddenFor(model => model)
<div class="btn-group btn-group-@htmlField">
  <button type="button"
          class="btn btn-default @levelOne bool-@htmlField"
          onclick="javascript: setValue(this, 1);">
    Level 1
  </button>
  <button type="button"
          class="btn btn-default @levelTwo bool-@htmlField"
          onclick="javascript:setValue(this, 2);">
    Level 2
  </button>
</div>

<script>
  function setValue(button, level) {
    $('.btn-group-@htmlField button.active').removeClass('active btn-primary');
    $(button).addClass('active btn-primary');
    $('#@htmlField').val(level); // TODO: Set the value of the model here
  }
</script>

Solution

  • It comes down to binding. The editor template is instantiated once (with an empty model object) when the grid is created and then hidden. When you click "Edit" the editor is placed into the DOM, replacing the display row, and the values in the dataSource object are bound to the inputs in the editor template (by name, I think). With standard or kendo inputs this causes the editor to update and display the correct value. With a complex editor (or a complex object) the binding essentially fails and goes no further.

    In your case, you can add an event handler to the Grid's edit event that will force the button to update to the input value when the editor is shown.