This is a migrated thread and some comments may be shown as answers.

KendoUI grid not calling controller on batch save

2 Answers 381 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Dan
Top achievements
Rank 2
Dan asked on 05 Dec 2012, 08:56 PM
Hi folks, I have been trying to figure out why my KendoUI grid will not call the controller when attempting to batch save.  As part of my troubleshooting, I created a number of ActionResults with different parameters and breakpointing in each one, hoping that I would hit one of these breakpoints.  No matter what method that I use in my view to call the controller to save, nothing happens.

I have two cascading Kendo DropDownLists (which work fine), and upon the user selecting an item in the second DropDownList, I populate a KendoUI grid via JSON.  The user can then fill in the New Rate field to whatever they want, and finally click a save button to batch update.  The user can increase (and later decrease, when I implement it) a percentage across the board via a TextBox and button.

I come from the ASPX and WinForms world, so jQuery and javascript in general are not my strong suits.

Here is the pertinent source code.  I added some javascript alerts, to help troubleshoot.  Note that the Kendo and jQuery scripts are referenced in a layout page as follows:
       <script src="@Url.Content("~/Scripts/jquery-1.8.3.min.js")" type="text/javascript"></script>
       <script src="@Url.Content("~/Scripts/kendo.web.min.js")" type="text/javascript"></script>
       <script src="@Url.Content("~/Scripts/kendo.aspnetmvc.min.js")" type="text/javascript"></script>


ViewModel

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MyReloWorks.Service.Models.ServiceManager;
using System.ComponentModel.DataAnnotations;

namespace MRW_MVC.Areas.SM.Models
{
    public class SFRRatesVM
    {
        [Key]
        public int SFRID { get; set; }
        public int ModeID { get; set; }
        public int DistanceID { get; set; }
        public int MeasurementID { get; set; }
        [Display(Name = "Distance (Miles)")]
        public string Distance { get; set; }
        public decimal CurrentRate { get; set; }
        [Display(Name = "Effective Date")]
        public DateTime EffectiveDT { get; set; }
        public decimal NewRate { get; set; }
    }
}

Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MRW_MVC.Controllers;
using MyReloWorks.Service.Services;
using MRW_MVC.Areas.SM.Models;
using Kendo.Mvc.Extensions;
using Kendo.Mvc.UI;
using MyReloWorks.Service.Models.ServiceProvider;
using MyReloWorks.Service.Models.ServiceManager;

namespace MRW_MVC.Areas.SM.Controllers
{
    [Authorize(Roles = "SM-Manager-HHG")]
    public class SFREntryController : AuthenticationController
    {
        private ISMService _smSerivce;
        private IShipmentService _shipmentService;

        public SFREntryController(ISMService smService, IShipmentService shipmentService)
        {
            _smSerivce = smService;
            _shipmentService = shipmentService;
        }

        public ActionResult Index()
        {
            return View();
        }

        public JsonResult GetCascadeModes()
        {
            var modeList = _shipmentService.GetMode("HHG");
            return Json(modeList.Select(m => new { ModeID = m.ModeID, ModeName = m.ModeDesc }), JsonRequestBehavior.AllowGet);
        }

        public JsonResult GetCascadeMeasurements(string modes)
        {
            var modeID = Convert.ToInt32(modes);
            var measurementList = _smSerivce.GetMeasurementsByModeID(modeID);              
            return Json(measurementList.Select(m => new { MeasurementID = m.MeasurementID, MeasurementName = m.MeasurementValue }), JsonRequestBehavior.AllowGet);
        }

        public JsonResult GetRates([DataSourceRequest]DataSourceRequest request, string mode, string measurement)
        {
            IList<SFRRatesVM> vm = new List<SFRRatesVM>();

            if (mode != "" && measurement != "")
            {
                var modeID = Convert.ToInt32(mode);
                var measurementID = Convert.ToInt32(measurement);
                var rates = _smSerivce.GetSFRRatesByModeIDAndMeasurementID(modeID, measurementID);

                //place data into the ViewModel's format
                foreach (SFRDTO rate in rates)
                {
                    var temp = new SFRRatesVM();
                    {
                        temp.SFRID = rate.SFRID;
                        temp.DistanceID = rate.DistanceID;
                        temp.ModeID = rate.ModeID;
                        temp.MeasurementID = rate.MeasurementID;
                        temp.Distance = rate.DistanceInfo.DistanceDesc;
                        temp.CurrentRate = rate.Rate;
                        temp.EffectiveDT = rate.EffectiveDT;
                        vm.Add(temp);
                    }
                }
                
            }
            DataSourceResult result = vm.ToDataSourceResult(request);
            return Json(result, JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public ActionResult UpdateRates()
        {
            throw new NotImplementedException();
        }

        public ActionResult UpdateRates(Models.SFRRatesVM request)
        {
            throw new NotImplementedException();
        }


        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult UpdateRates([DataSourceRequest] DataSourceRequest request, IEnumerable<SFRRatesVM> vm)
        {
            //TODO: handle multiple modes
            if (vm != null && ModelState.IsValid)
            {
                //get the old rates
                var oldRates = _smSerivce.GetLiftVanRates();

                // for each DistanceID, check the old rate to the "new" rate, and update accordingly
                foreach (SFRRatesVM rate in vm)
                {
                    var temp = new SFRDTO();
                    {
                        temp = oldRates.Where(r => r.SFRID == rate.SFRID).FirstOrDefault();
                        if (temp.Rate != rate.NewRate)
                        {
                            _smSerivce.UpdateSFRRate(temp, rate.NewRate);
                        }
                    }
                }
            }
            return Json(ModelState.ToDataSourceResult());
        }

        [HttpPost]
        public ActionResult UpdateRates(IEnumerable<SFRRatesVM> vm)
        {
            //TODO: handle multiple modes
            if (vm != null && ModelState.IsValid)
            {
                //get the old rates
                var oldRates = _smSerivce.GetLiftVanRates();

                // for each DistanceID, check the old rate to the "new" rate, and update accordingly
                foreach (SFRRatesVM rate in vm)
                {
                    var temp = new SFRDTO();
                    {
                        temp = oldRates.Where(r => r.SFRID == rate.SFRID).FirstOrDefault();
                        if (temp.Rate != rate.NewRate)
                        {
                            _smSerivce.UpdateSFRRate(temp, rate.NewRate);
                        }
                    }
                }
            }
            return Json(ModelState.ToDataSourceResult());
        }

        public ActionResult GenerateReport()
        {
            return View();
        }
    }
}


View:
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Service Management - Manage SFR Rates</h2>

        <label for="modes">Modes:</label>
        @(Html.Kendo().DropDownList()
            .Name("modes")
            .OptionLabel("Select a mode..")
            .DataTextField("ModeName")
            .DataValueField("ModeID")          
            .DataSource(source =>
            {
                source.Read(read =>
                {
                    read.Action("GetCascadeModes", "SFREntry");
                });
            })
        )
    
        <label for="measurements">Measurements:</label>
        @(Html.Kendo().DropDownList()
            .Name("measurements")
            .OptionLabel("Select a measurement...")
            .DataTextField("MeasurementName")
            .DataValueField("MeasurementID")
            .DataSource(source =>
            {
                source.Read(read =>
                {
                    read.Action("GetCascadeMeasurements", "SFREntry")
                        .Data("filterMeasurements");
                })
                .ServerFiltering(true);
            })
            .Events(e => e.Change("measurementChanged"))
            .Enable(false)
            .AutoBind(false)
            .CascadeFrom("modes")
        )

    <br />
    <br />

        @(Html.Kendo().Grid<MRW_MVC.Areas.SM.Models.SFRRatesVM>()
            .Name("myGrid")
            .HtmlAttributes(new { style = "width:500px" })
            .Columns(columns => {
                columns.Bound(p => p.SFRID).Hidden();
                columns.Bound(p => p.Distance).Width(25);
                columns.Bound(p => p.CurrentRate)
                    .Format("{0:C}")
                    .Width(25)
                    .HtmlAttributes(new { style = "text-align: right" });
                columns.Bound(p => p.EffectiveDT)
                    .Format("{0:d}")
                    .Width(25);
                columns.Bound(p => p.NewRate)
                    .Format("{0:C}")
                    .Width(25)
                    .HtmlAttributes(new { style = "text-align: right" });
            })
            .Editable(editable => editable.Mode(GridEditMode.InCell))
            .Resizable(resize => resize.Columns(true))
            .AutoBind(false)
            .Events(events =>
            {
                events.SaveChanges("onSaveChanges");
            })
            .ToolBar(toolbar=> toolbar.Save())
            .DataSource(dataSource => dataSource
                .Ajax()
                .Events(events => events.Error("error_handler"))
                .Batch(true)
                .Model(model => 
                {
                    model.Id(p => p.SFRID);
                    model.Field(p => p.Distance).Editable(false);
                    model.Field(p => p.CurrentRate).Editable(false);
                    model.Field(p => p.EffectiveDT).Editable(false);
                    model.Field(p => p.NewRate).Editable(true);
                })
                .Update(update => update.Action("UpdateRates", "SFREntry").Data("getGridData"))
                .Create(create => create.Action("UpdateRates", "SFREntry").Data("getGridData"))
                .Read(read => read.Action("GetRates", "SFREntry").Data("getModeAndMeasurement"))
           )     
        )

        <br />
        <button id="btnGo" type="button">Go</button>               
        <br />
        
        @Html.Label("Adjust Rates (By %)")
        <br />
        <input type="text" id="txtRate" size="100" />    
        @Html.RadioButton("Adjust", true)Down
        &nbsp;&nbsp;    
        @Html.RadioButton("Adjust", false)Up
        <br />  
        <button id="btnAdjust" type="button">Adjust</button>                  

    <script type="text/javascript">
        function filterMeasurements() {
            return {
                modes: $("#modes").val()
            };
        }

        function getModeAndMeasurement() {
            var measurement = $("#measurements").val();
            var mode = $("#modes").val();
            return {
                mode: mode,
                measurement: measurement
            };
        }

        function measurementChanged() {
            var grid = $("#myGrid").data("kendoGrid");
            grid.dataSource.read();          
        }

        function error_handler(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 () {
            $("#btnGo").click(function () {
                alert('starting POST');
                $.ajax({
                    url: '@Url.Action("UpdateRates ", "SFREntry", Request.RequestContext.RouteData.Values)',
                    type: 'POST',
                    cache: false,
                    traditional: true,
                    dataType: "json",
                    contentType: "application/json",
                    data: kendo.stringify({
                        vm: $("#myGrid").data("kendoGrid").dataSource.view().toJSON()
                    }),
                    success: function () { window.alert('saved'); },
                    error: function() { window.alert('failed'); }
                });
                alert('ending POST');
            });
        });

        function getGridData() {
             var grid = $("#myGrid").data("kendoGrid");
             var vm = grid.dataSource.view();
             alert(vm);
             return vm;
        }

        //test to see if the save event fires
        function onSaveChanges(e) {
            var grid = $("#myGrid").data("kendoGrid");
            var data = grid.dataSource.view();
            var count = data.length;
            alert('In onSaveChanges');
            alert(count);
        }

        //fill in the New Rates column with the old rate, multiplied by amount in txtRate
        $(function () {
            $("#btnAdjust").click(function () {
                var adjustment = $("#txtRate").val() / 100;
                var grid = $("#myGrid").data("kendoGrid");
                var data = grid.dataSource.view();
                var count = data.length;
                for (var i = 0; i < count; i++) {
                    var currentRow = data[i];
                    var currentRate = currentRow.CurrentRate;
                    currentRow.NewRate = (currentRate + (currentRate * adjustment));
                };
                grid.refresh();
            });
        });
    </script>  

Thanks!

--Dan

2 Answers, 1 is accepted

Sort by
0
Vladimir Iliev
Telerik team
answered on 07 Dec 2012, 12:03 PM
Hi Daniel,

 
After reviewing the provided project it seems that there are several parts of the code that need to be updated:

  1. jQuery used in the project is not supported - please change it to v.1.8.2.
  2. You should remove all Actions with name "UpdateRates" and add the following one which accepts IEnumerable collection with prefix 'models':
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult UpdateRates([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<SFRRatesVM> vm)
    {
        //execute your custom logic
        return Json(ModelState.ToDataSourceResult());
    }

After making the above changes if the Grid Update action still not getting to the Controller you should provide run-able project where the issue is reproduced - hopefully this will help us pinpoint the exact reason for this behavior. 

Kind Regards,
Vladimir Iliev
the Telerik team
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Dan
Top achievements
Rank 2
answered on 07 Dec 2012, 06:16 PM
Thank you for the response.  

My team (surprisingly) never updated the jQuery references in the project.  I updated them all to v1.8.3 (the latest in NuGet), and everything works.
Tags
Grid
Asked by
Dan
Top achievements
Rank 2
Answers by
Vladimir Iliev
Telerik team
Dan
Top achievements
Rank 2
Share this question
or