title: Telerik Kendo UI Grid MVC - Programmatically Cancel Edits
body: <p>During editing of the grid, I need to validate the data input and if it fails validation, I need to revert the bad data back to an unchanged state so it won't get saved (akin to using the Reset button, but just for the current row being editing...this is a batch editing grid). </p>
  
  <p>Using the javascript code below, I can identify the problem, throw up the alert, but after the user accepts the alert, they could still just click the Save button and it would save that way, with the incorrect data.</p>
  
  <p>To combat this, you'll see I try to set the e.values and e.model to 0, but it is not working (no error is thrown, it just doesn't change the value in the grid).</p>
  
  <p>Maybe I need to identify the DOM element and change it's value directly, but I couldn't find how to retrieve the DOM element from the e object.</p>
  
  <pre><code>function beforeCartonPackUpdates(e) {
      if (e.values.QtyToPack &gt; e.model.OrderedQty) {
          alert("ERROR! You cannot pack more than was ordered.");
          e.model.set("QtyToPack", 0);
          e.values.QtyToPack = 0;
          return false;
      }
  
      if (e.values.QtyToPack &gt; e.model.RemainingToPack) {
          alert("Warning! You are packing more than is available.");
          return true;
      }
  }
  
  @(Html.Kendo().Grid&lt;OTIS.AppServ.OrderMgmt.ViewModels.ShipOrderDetailViewModel&gt;()
      .Name("ShipOrderDtlsGrid")
      .HtmlAttributes(new { style = "width:100%;" })
      .Resizable(resize =&gt; resize.Columns(true))
      .Columns(columns =&gt;
      {
          columns.Bound(l =&gt; l.Id).Hidden();
          columns.Bound(l =&gt; l.OrderHeaderId).Hidden();
          columns.Bound(l =&gt; l.StatusId).Hidden();
          columns.Bound(l =&gt; l.ItemId)
              .ClientTemplate("&lt;a href='" +
                                      Url.Action("Edit", "ManageItems", new { area = "InventoryMgmt" }) +
                                      "/#= ItemId #'" +
                                  " target='_blank'&gt;#= ItemDescription #&lt;/a&gt;"
                              )
              .ClientFooterTemplate("#=kendo.format('Line Count: {0:n0}', count)#");
          columns.Bound(l =&gt; l.OrderedQty)
              .Title("Ord")
              .HeaderHtmlAttributes(new { style = "text-align:right;" })
              .HtmlAttributes(new { style = "text-align:right;" })
              .FooterHtmlAttributes(new { style = "text-align:right;" })
              .ClientFooterTemplate("#=kendo.format('{0:n2}', sum)#");
          columns.Bound(l =&gt; l.BackorderedQty)
              .Title("B/O")
              .HeaderHtmlAttributes(new { style = "text-align:right;" })
              .HtmlAttributes(new { style = "text-align:right;" })
              .FooterHtmlAttributes(new { style = "text-align:right;" })
              .ClientFooterTemplate("#=kendo.format('{0:n2}', sum)#");
          columns.Bound(l =&gt; l.PickedQty)
              .Title("Pick")
              .HeaderHtmlAttributes(new { style = "text-align:right;" })
              .HtmlAttributes(new { style = "text-align:right;" })
              .FooterHtmlAttributes(new { style = "text-align:right;" })
              .ClientFooterTemplate("#=kendo.format('{0:n2}', sum)#");
          columns.Bound(l =&gt; l.PackedQty)
              .Title("Pack")
              .HeaderHtmlAttributes(new { style = "text-align:right;" })
              .HtmlAttributes(new { style = "text-align:right;" })
              .FooterHtmlAttributes(new { style = "text-align:right;" })
              .ClientFooterTemplate("#=kendo.format('{0:n2}', sum)#");
          columns.Bound(l =&gt; l.RemainingToPack)
              .Title("Remain")
              .HeaderHtmlAttributes(new { style = "text-align:right;" })
              .HtmlAttributes(new { style = "text-align:right;" })
              .FooterHtmlAttributes(new { style = "text-align:right;" })
              .ClientFooterTemplate("#=kendo.format('{0:n2}', sum)#");
          columns.Bound(l =&gt; l.QtyToPack)
              .HeaderHtmlAttributes(new { style = "text-align:right;" })
              .HtmlAttributes(new { @class = "editable", style = "text-align:right;" })
              .FooterHtmlAttributes(new { style = "text-align:right;" })
              .ClientFooterTemplate("#=kendo.format('{0:n2}', sum)#");
          //columns.Command(command =&gt;
          //    {
          //        command.Edit();
          //        command.Destroy();
          //    }).Width(180);
      })
      .Editable(editing =&gt; editing.Mode(GridEditMode.InCell))
      .Events(events =&gt;
      {
          //events.SaveChanges("afterCartonPackUpdates"); //fires BEFORE saving - good place to do validation
          events.Save("beforeCartonPackUpdates"); //fires Before saving, but as soon as cell value changes, better place to do validation
          events.SaveChanges("preCartonPackUpdates");//fires AFTER .Save but before calling destroy method
      }
      )
          // Add "Create" command
      .ToolBar(toolbar =&gt;
      {
          //toolbar.Create().Text("Add Work Order Detail");
          toolbar.Template(@&lt;text&gt;@RenderOrderDetailsToolBar()&lt;/text&gt;);
          //toolbar.Custom().Text("&lt;span class='k-icon k-cancel'&gt;&lt;/span&gt;Cancel&lt;/text&gt;").Url("##_").HtmlAttributes(new { @class = "k-grid-cancel-changes" });
          //toolbar.Custom().Text("&lt;span class='k-icon k-update'&gt;&lt;/span&gt;Pack&lt;/text&gt;").Url("##_").HtmlAttributes(new { @class = "k-grid-save-changes" });
          //toolbar.Save();
      })
  
      .DataSource(dataSource =&gt; dataSource
          .Ajax() // Specify that the data source is of ajax type
          .Aggregates(aggregates =&gt;
          {
              aggregates.Add(x =&gt; x.ItemId).Count();
              aggregates.Add(x =&gt; x.OrderedQty).Sum();
              aggregates.Add(x =&gt; x.PickedQty).Sum();
              aggregates.Add(x =&gt; x.RemainingToPack).Sum();
              aggregates.Add(x =&gt; x.QtyToPack).Sum();
              aggregates.Add(x =&gt; x.PackedQty).Sum();
              aggregates.Add(x =&gt; x.BackorderedQty).Sum();
          })
          .Batch(true)
          .Model(model =&gt;
          {
              model.Id(c =&gt; c.Id);
              model.Field(c =&gt; c.OrderHeaderId).DefaultValue(Model.Id);
              model.Field(c =&gt; c.UnitCost).Editable(false);
              model.Field(c =&gt; c.ItemDescription).Editable(false);
              model.Field(c =&gt; c.OrderedQty).Editable(false);
              model.Field(c =&gt; c.PickedQty).Editable(false);
              model.Field(c =&gt; c.PackedQty).Editable(false);
              model.Field(c =&gt; c.BackorderedQty).Editable(false);
          }
          )
          .Sort(sort =&gt;
          {
              sort.Add(c =&gt; c.ItemDescription);
          })
  
          .Events(events =&gt;
          {
              events.Error("KendoGridErrors");// Specify a handler for the error event
              events.RequestEnd("onPackCartonGridComplete");
          }
          )
          // CRUD configuration --&gt;
          //.Create(create =&gt; create.Action("Grid_SaveOrUpdate", "ManageWorkOrders", new { area = "OrderMgmt" }).Type(HttpVerbs.Post))
          .Read(read =&gt; read.Action("GetShipOrderDetails", "ManageShipOrders", new { area = "OrderMgmt", intOrderHeaderId = @Model.Id })// Specify the action method and controller name
                  .Type(HttpVerbs.Get)
          )
          .Update(update =&gt; update.Action("CreateCartonAndPack", "ManageShippingContainers", new { area = "OrderMgmt" }).Type(HttpVerbs.Post))
          //.Destroy(destroy =&gt; destroy.Action("Grid_Delete", "ManageWorkOrders", new { area = "OrderMgmt" }).Type(HttpVerbs.Post))
          // &lt;-- CRUD configuration
      )
      .Sortable()
  )    
  </code></pre>