Prevent kendo ui grid popup editor from closing after validation errors

6 posts, 0 answers
  1. west
    west avatar
    1 posts
    Member since:
    Jan 2017

    Posted 19 Jan 2017 Link to this post

    I am returning errors from server and catch it in kendo datasource error event.In this event I am trying to prevent close popup editor, but it works only first time, after clicking update second time, the window closes.
    I searched a lot but could not find a solution

     

    City = {
        InitializeGrid: function () {
     
            function LoadCities(url, success) {
                Common.serverRequest(url, success);
            }
     
            function UpdateCity(url, params, success) {
                Common.serverRequestParams(url, params, success);
            }
     
            function InsertCity(url, params, success) {
                Common.serverRequestParams(url, params, success);
            }
     
            function DeleteCity(url, id, success) {
                Common.serverRequestParams(url, id, success);
            }
     
            dataSource = new kendo.data.DataSource({
                transport: {
                    read: function (e) {
                        LoadCities("/home/read", function (res) {
                            e.success(res);
                        });
                    },
     
                    update: function (e) {
     
                        UpdateCity("/home/update", e.data, function (res) {
                            var grid = $("#grid").data("kendoGrid");
                            if (res.success) {
                                grid.dataSource.read();
                            } else {
                                e.error("", "", res.error);
                                grid.cancelChanges();
                            }
     
                        });
                    },
                    create: function (e) {
                        InsertCity("/home/insert", e.data, function (res) {
                            var grid = $("#grid").data("kendoGrid");
     
                            if (res.success) {
                                grid.dataSource.data(res.data);
                            } else {
                                e.error("", "", res.error);
                                grid.cancelChanges();
                            }
                        });
                    },
                    destroy: function (e) {
                        DeleteCity("/home/delete", e.data, function (res) {
                            var grid = $("#grid").data("kendoGrid");
     
                            if (res.success) {
                                grid.dataSource.data(res.data);
                            } else {
                                e.error("", "", res.error);
                                grid.cancelChanges();
                            }
     
                        });
                    }
                },
                error: function (e) {
                    var grid = $("#grid").data("kendoGrid");
                    grid.one("dataBinding", function (e) {
                        e.preventDefault(); // it occures only first time
                    });
                    alert(e.errorThrown);
     
                },
                pageSize: 20,
                schema: {
                    model: {
                        id: "Id",
                        fields: {
                            Name: { type: "string" },
                            EndDate: { type: "date" },
                            CreateDate: { type: "date" }
                        }
                    }
                }
            });
     
            $("#grid").kendoGrid({
                dataSource: dataSource,
                height: 750,
                selectable: "single",
                filterable: true,
                sortable: true,
                pageable: true,
                toolbar: [{ name: "newRecord", text: "New Record" }, { name: "editRecord", text: "Edit REcord" }, { name: "deleteRecord", text: "Delete" }],
                columns: [
                    { field: "Name", title: "Name" },
                    { field: "EndDate", title: "End Date", format: "{0:dd.MM.yyyy hh:mm}" },
                    { field: "CreateDate", title: "Create Date", format: "{0:dd.MM.yyyy hh:mm}" }
                ],
                editable: {
                    mode: "popup",
                    confirmation: false,
                    template: kendo.template($("#popup_editor").html())
                }
            });
     
            $("#grid").on("click", ".k-grid-newRecord", function () {
                Common.gridAdd('grid', 'New Record');
            });
     
            $("#grid").on("click", ".k-grid-editRecord", function () {
                Common.gridEdit('grid', 'Edit Record');
            });
     
            $("#grid").on("click", ".k-grid-deleteRecord", function () {
                Common.gridDelete('grid');
            });
     
        }
    }

     

    mvc controler

    public class HomeController : Controller
        {
            List<City> cities;
            public string error { get; set; }
            public bool isSuccess { get; set; } = true;
             
     
            public ActionResult Index()
            {
                cities = new List<City>();
                Session["city"] = cities;
                return View();
            }
     
            public ActionResult Read()
            {
                var result = (List<City>)Session["city"];
                return Json(result);
            }
     
            public ActionResult Update(City item)
            {
                var result = (List<City>)Session["city"];
     
                if (string.IsNullOrEmpty(item.Name))
                {
                    error = "Name is required";
                    isSuccess = false;
                }
     
                result.Where(w => w.Id == item.Id).SingleOrDefault(s => s == item);
     
                return Json(new { success = isSuccess, error =error, data = item });
            }
     
            public ActionResult Insert(City item)
            {
                var result = (List<City>)Session["city"];
     
                item.Id = result.Count;
                item.Id++;
     
                if (string.IsNullOrEmpty(item.Name))
                {
                    error = "Name is required";
                    isSuccess = false;
                }
     
                result.Add(item);
     
                return Json(new { success = isSuccess, error = error, data = item });
            }
     
            public ActionResult Delete(City item)
            {
                var result = (List<City>)Session["city"];
     
                result.Remove(item);
     
                return Json(new { success = isSuccess });
            }
        }
  2. Alex Hajigeorgieva
    Admin
    Alex Hajigeorgieva avatar
    1082 posts

    Posted 23 Jan 2017 Link to this post

    Hello West,

    If I understand you correctly, you need to prevent the Kendo UI Grid popup editable window from closing when the entered data is invalid. This behaviour is built-in when the schema model field validation object is configured:

    http://docs.telerik.com/kendo-ui/api/javascript/data/model#methods-Model.define 

    A demo which shows both the built-in validation as well as a custom rule is shown in the official demos site here:

    http://demos.telerik.com/kendo-ui/grid/editing-custom-validation

    Finally, I would like to propose removing the Kendo UI Grid logic from the data source entirely. Since the data source is bound to the grid, the grid will get updated automatically. Just call e.success/e.error for the create, update and delete operations( the read operation is grid-free so it can stay that way). I believe the code should be something similar to the below:

    update: function (e) {
     UpdateCity("/home/update", e.data, function (res) {
      if (res.success) {
        e.success()
       } else {
        e.error("", "", res.error);
       }
     });
    },
    create: function (e) {
     InsertCity("/home/insert", e.data, function (res) {
      if (res.success) {
         e.success(e.data);
      } else {
         e.error("", "", res.error);
      }
     });
    },
    destroy: function (e) {
     DeleteCity("/home/delete", e.data, function (res) {
      if (res.success) {
         e.success();
      } else {
         e.error("", "", res.error);
      }
     });
    }

    Let me know if I misunderstood the question, so I can promptly provide a more appropriate response.

    Kind Regards,
    Alex Hajigeorgieva
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  3. riz
    riz avatar
    11 posts
    Member since:
    Feb 2018

    Posted 21 May 2019 in reply to Alex Hajigeorgieva Link to this post

    I'm not the original poster, but am in a similar situation. It seems that you have misunderstood the original question as the poster states in their first line: "I am returning errors from server and catch it in kendo datasource error event."  Whereas you are talking about doing input model validation on the client side, the user is talking about errors being returned from the server. Once the client input validation is successful, we still have to validate on the backend, and the popup should still remain open if the validation fails on the server end to allow the user to fix the errors otherwise it's frustrating to re-enter the data. Do you have a solution for this?
  4. Alex Hajigeorgieva
    Admin
    Alex Hajigeorgieva avatar
    1082 posts

    Posted 23 May 2019 Link to this post

    Hi, Riz,

    Thank you for noting that the original poster has described a data source error which is coming from a remote service. I believe you are correct and that I have misunderstood the post.

    I created a sample Dojo  using a mocked error response here that shows how to keep the popup open and notify the errors:

    https://dojo.telerik.com/@bubblemaster/OGUlAKIL

    Here are the important parts: 

    - specify which part of the response contains the errors

    https://docs.telerik.com/kendo-ui/api/javascript/data/datasource/configuration/schema#schemaerrors 

    - add an error handler in the data source. It will be triggered when the field which contains the errors is present in the response
    - prevent the grid to bind. This will keep the popup open and notify the user that there are errors:

    // data source error handler 
    error: function(e) {
      grid.one("dataBinding", function (ev) {
        ev.preventDefault();
        var message = "Errors:\n";           
        $.each(e.errors, function (idx, error) {            
           message += "Code: "
             + error.code
             + " | Reason: " + error.reason
             + "\n";
        });
        kendo.alert(message);
      });
    }

    I hope this helps.

    Kind Regards,

    Alex Hajigeorgieva
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  5. riz
    riz avatar
    11 posts
    Member since:
    Feb 2018

    Posted 28 Jun 2019 in reply to Alex Hajigeorgieva Link to this post

    Thanks Alex, but I am getting an error "Uncaught TypeError: Cannot read property 'one' of undefined".  I think in this case 'dataBinding' parameter is the name of the grid?  My error handler in this case is generic and my application has many grids possibly with different names, so I can't explicitly specify the name of the grid as you have. Is there a way to fetch the name of the grid from the 'e' parameter of the error handler?
  6. Alex Hajigeorgieva
    Admin
    Alex Hajigeorgieva avatar
    1082 posts

    Posted 02 Jul 2019 Link to this post

    Hello, Riz,

    The Kendo UI DataSource has no knowledge of the grid or other data bound widgets to which it could be simultaneously bound to. So the error event which the data source emits and its event data cannot give us the grid's instance. This is done on purpose to comply with quality code and the Separation of Concerns design principle.

    In your scenario, do you have the same data source bound to different grids on the same page? Could you please provide an example of the exact case in which you are not able to get the grid instance?

    I am unsure if this would help but each grid has a data-role="grid" attribute and if only one grid is in edit mode, perhaps we could use that to get to the correct instance.

    Look forward to hearing back from you so I can better understand the details.

    Regards,
    Alex Hajigeorgieva
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Back to Top