Grid, extra entry if I enter two items in a row

3 posts, 1 answers
  1. Answer
    Jon Smith
    Jon Smith avatar
    2 posts
    Member since:
    Mar 2011

    Posted 25 Apr 2013 Link to this post

    I have an MVC4 application with a MVC defined Grid with CRUD operation. I am using inline Create and get a strange phenomena when I enter two entries in a row. The scenario is as follows:
    1.  I click 'Add New Item' button and an empty row appears at the top of the grid with the two editable items open for input.
    2. I enter the date new entry and click the 'Update' button.
    3. I see a single POST go back to the MVC application and the create works correctly.
    4. As the next immediate step I then press 'Add New Item' button again and enter  a new entry.
    5. On pressing the 'Update' button I see TWO Posts go back to the MVC application.
             - The first is the new entry
             - The second is the data for the entry entered in steps 1 to 3.

    That is rather strange, and my database, which does not allow entries with the same name fails the second (duplicate) entry. If I press F5 or next page on the grid after step 3 then I do not have this problem.

    My .razor view is:

    @{
        ViewBag.Title = "Services";
    }
     
    <h2>Services</h2>
     
    @*<div id="message" class="Message"></div>*@
    @Html.AntiForgeryToken()
     
    @(Html.Kendo().Grid<ServiceLayer.Models.DTOs.SmServiceDto>()
          .Name("Services")
          .Columns(columns =>
                       {
                           columns.Bound(p => p.SmServiceId).Hidden();
                           columns.Bound(p => p.ShortName);
                           columns.Bound(p => p.FullName);
                           columns.Bound(p => p.Locked);
                           columns.Command(command => { command.Edit(); command.Destroy(); }).Width(172);
                       })
          .ToolBar(toolbar => toolbar.Create())
          .Editable(editable => editable.Mode(GridEditMode.InLine))
          .Pageable()
          .Sortable()
          //.Scrollable()
          //.HtmlAttributes(new {style = "height:430px;"})
          .DataSource(dataSource => dataSource
                                        .Ajax()                               
                                        .PageSize(10)
                                        .Events(events => events.Error("error_handler"))
                                        .Model(model =>
                                                   {
                                                       model.Id(p => p.SmServiceId);
                                                       model.Field(x => x.SmServiceId).Editable(false);
                                                       model.Field(x => x.Locked).Editable(false);
                                                   })
                                        .Create(x => x.Action("AjaxServiceCreate", "Model").Data("sendAntiForgery").Type( HttpVerbs.Post))
                                        .Read(read => read.Action("AjaxServiceRead", "Model"))
                                        .Update(x => x.Action("AjaxServiceUpdate", "Model").Type( HttpVerbs.Post).Data("sendAntiForgery"))
                                        .Destroy(x => x.Action("AjaxServiceDelete", "Model").Type( HttpVerbs.Post).Data("sendAntiForgery"))
          ))
           
    @section scripts {
    <script type="text/javascript">
        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 sendAntiForgery() {
            return { "__RequestVerificationToken": $('input[name=__RequestVerificationToken]').val() };
        }
     
    </script>
    }

    The MVC actions are pretty standard copies of the format on your examples site, but with ValidateAntiForgeryToken added.

    [AllowAnonymous]
            public ActionResult Services(IListSmService service)
            {
                return View();
            }
     
            [AllowAnonymous]
            public ActionResult AjaxServiceRead([DataSourceRequest]DataSourceRequest request, IListSmService service)
            {
                return Json(service.GetList().ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
            }
     
            [AllowAnonymous]
            [AcceptVerbs(HttpVerbs.Post)]
            [ValidateAntiForgeryToken]
            public ActionResult AjaxServiceCreate([DataSourceRequest] DataSourceRequest request, ISmServiceDto newItem, ICreateSmService service)
            {
                if (newItem != null && ModelState.IsValid)
                {
                    var response = service.Create(newItem);
                    if (!response.IsValid)
                        //errors, so copy the errors over to the ModelState
                        response.CopyErrorsToModelState(ModelState);
                }
     
                return Json(new[] { newItem }.ToDataSourceResult(request, ModelState));
            }
     
            [AllowAnonymous]
            [AcceptVerbs(HttpVerbs.Post)]
            [ValidateAntiForgeryToken]
            public ActionResult AjaxServiceDelete([DataSourceRequest] DataSourceRequest request, ISmServiceDto itemToDelete, IDeleteSmService service)
            {
                if (itemToDelete != null)
                {
                    var response = service.Delete(itemToDelete.SmServiceId);
                    if (!response.IsValid)
                        //errors, so copy the errors over to the ModelState
                        response.CopyErrorsToModelState(ModelState);
                }
     
                return Json(ModelState.ToDataSourceResult());
            }

    I must be doing wrong but I can't see it. Your help would be appreciated.

  2. Daniel
    Admin
    Daniel avatar
    2219 posts

    Posted 29 Apr 2013 Link to this post

    Hello,

    Does the service.Create method assign the ID to the new item? The dataSource uses the item ID to determine if the item is new so a request will be sent again to create the item if the ID is not assigned.

    Regards,
    Daniel
    the Telerik team
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  3. Jon Smith
    Jon Smith avatar
    2 posts
    Member since:
    Mar 2011

    Posted 29 Apr 2013 Link to this post

    Hi Daniel,

    Thank you. That was the problem and I marked this as fixed. I had to change my ICreateSmService service to set the Key in the dto class and that fixed it.

    Would you be so kind as to provide a link to the documentation where this specific issue is described as there may be other things I have missed too. It was a nasty bug to find.

    Thanks.
Back to Top