Sorting and Filtering for Custom Object in Column doesn't work

4 posts, 2 answers
  1. Answer
    Helga
    Helga avatar
    3 posts
    Member since:
    Jan 2013

    Posted 15 Oct 2013 Link to this post

    Hello,
    i'm new to KendoGrid and this is my first Project. I hope you can help me and forgive my bad english ;)

    The Problem:
    If I bind another Object to a Column which is included in the Object of the Row, sorting and filtering doesn't work anymore.
    Each Row, I bind a "Adress" Object, include a "Country" Object. I use a ClientTemplate to show the "Description" Property (if not null).
    I know that a ClientTemplate breaks the Sorting and Filtering, but i don't know how to solve this by the MVC Wrapper. I found no examples.

    In Inline-Editormode I display for the Country-Object a Kendo-DropDownList for valid values. This works fine for CRUD.
    For the Country Column in Read-Mode I've added a Custom Filter with a Kendo-DropdownList for the valid values, but there is a empty DropDownList for the Filter-Options (for ex. "ss equal to"...). So if i press "Filter" or sorting the Column, the Grid don't know how to sort/filter.

    PS.: The Country is attached/connected by the EntityFramework(Designer) and the Models were created automatically.

    The Question:
    How can i solve my Problem? How can i implement with the MVC Wrapper a working sorting/filtering for an Object in a Column? And.... is there a better solution to bind a Object to a Column with a DropDownList?

    Thank you for your help :)

    Grid View
    @{
        Layout = "~/Views/Shared/Layout.cshtml";
    }
     
    @model IEnumerable<LiCPSAdmin2.Models.Adressen>
     
    @(Html.Kendo().Grid(Model)
        .Name("Adressen")
        .Columns(columns =>
        {
            columns.Command(command =>
            {
                command.Edit().Text(" ");
                command.Destroy().Text(" ");
            }).Width(90).HtmlAttributes(new { style = "background-color: rgb(238, 238, 238)" });
            columns.Bound(p => p.Eadr).Title("Adresse").Width(90).HtmlAttributes(new { style = "text-align:center;" });
            columns.Bound(p => p.Nama).Title("Name").Width(200);
            columns.Bound(p => p.Namb).Title("Name 2").Width(200);
            columns.Bound(p => p.Namc).Title("Strasse");
            columns.Bound(p => p.Namd).Title("Strasse 2");
            columns.Bound(p => p.Name).Title("Plz, Ort");
            columns.Bound(p => p.Namf).Title("Ort 2");
            columns.Bound(p => p.Pstc).Title("PLZ").Width(90).HtmlAttributes(new { style = "text-align:center;" });
            columns.Bound(p => p.Ccty).Title("Land").Width(90).HtmlAttributes(new { style = "text-align:center;" });
            columns.Bound(p => p.BaLand).Title("Bezeichnung").Width(200).ClientTemplate(" #= BaLand ? BaLand.Dsca : '' # ").Filterable(filter => filter.UI("BaLandFilter"));
        })
        .DataSource(dataSource => dataSource
            .Ajax()
            .PageSize(50)
            .Model(model =>
            {
                model.Id(p => p.Eadr);
                model.Field(p => p.Eadr).Editable(false);
            })
            .Events(events => events.Error("error_handler"))
            .Create(create => create.Action("Create", "Adressen"))
            .Read(read => read.Action("Read", "Adressen"))
            .Update(update => update.Action("Edit", "Adressen"))
            .Destroy(destroy => destroy.Action("Delete", "Adressen"))
        )
        .Events(events => events.Edit("edit_handler"))
        .ToolBar(toolbar => toolbar.Create())
        .Editable(editable => editable.Mode(GridEditMode.InLine))
        .Sortable(sortable => sortable.AllowUnsort(true).SortMode(GridSortMode.MultipleColumn))
        .Filterable(filter => filter.Extra(false))
        .ColumnResizeHandleWidth(5)
        .Scrollable(scrollable => scrollable.Virtual(true))
        .HtmlAttributes(new { style = "height:100%;" })
        .Navigatable(nav => nav.Enabled(true))
        .Resizable(resize => resize.Columns(true))
        .Reorderable(reordering => reordering.Columns(true))
        .Pageable()
    )
     
    <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);
                var grid = $("#Adressen").data("kendoGrid");
                grid.cancelChanges();
            }
        };
     
        function baland_change() {
            $("#Ccty").val(this.value()).css({ 'background-color': '#fff' }).trigger("change");
        }
     
        function edit_handler(e) {
            $(".k-grid-update").html("<span class=\"k-icon k-update\"></span>");
            $(".k-grid-cancel").html("<span class=\"k-icon k-cancel\"></span>");
     
            e.container.find("#Ccty").focusout(function () {
                e.container.find("#BaLand").data("kendoDropDownList").value($(this).val());
            });
        }
     
        function BaLandFilter(element) {
            element.kendoDropDownList({
                dataSource: {
                    transport: {
                        read: "@Url.Action("FilterMenuCustomization_BaLand")"
                    }
                },
                optionLabel: "Bitte wählen"
            });
        }
     
    </script>
    Editor Template for Countries (BaLand)
    @(Html.Kendo().DropDownList()
        .Name("BaLand")
        .BindTo((System.Collections.IEnumerable)TempData["Land"])
        .DataTextField("Dsca")
        .DataValueField("Ccty")
        .OptionLabel("Bitte wählen")
        .Events(e => e
            .Change("baland_change")
        )
    )

    Adress Controller

    public class AdressenController : Controller
        {
            private LiCPS_Develop_V20Entities db = new LiCPS_Develop_V20Entities();
     
            protected override void Dispose(bool disposing)
            {
                db.Dispose();
                base.Dispose(disposing);
            }
     
            // Index
            public ActionResult Index()
            {
                TempData["Land"] = db.BaLand.ToList();
                var adressen = db.Adressen.Include(a => a.BaLand).Distinct();
                return View(adressen.ToList());
            }
     
            public ActionResult FilterMenuCustomization_BaLand()
            {
                return Json(db.BaLand.Select(e => e.Dsca).Distinct(), JsonRequestBehavior.AllowGet);
            }
     
            // Grid
            public ActionResult Read([DataSourceRequest] DataSourceRequest request)
            {
                return Json(((db.Adressen.Include(a => a.BaLand).Distinct()).ToList()).ToDataSourceResult(request));
            }
     
            [AcceptVerbs(HttpVerbs.Post)]
            public ActionResult Create([DataSourceRequest] DataSourceRequest request, Adressen adressen)
            {
                if (adressen != null && ModelState.IsValid)
                {
                    adressen.Eadr = Convert.ToInt32(HelperFunctions.getNextNumber(10, 2));
                    db.Adressen.Add(adressen);
                    db.Entry(adressen.BaLand).State = EntityState.Unchanged;
                    
                    try
                    {
                        db.SaveChanges();
                    }
                    catch (InvalidOperationException ex)
                    {
                        ModelState.AddModelError(string.Empty, "Es ist ein Fehler aufgetreten! Der Datensatz wurde nicht erstellt");
                    }
                    catch (DbEntityValidationException ex)
                    {
                        ModelState.AddModelError(string.Empty, "Es ist ein Fehler aufgetreten! Der Datensatz wurde nicht erstellt");
                    }
                    catch (DbUpdateException ex)
                    {
                        ModelState.AddModelError(string.Empty, "Es ist ein Fehler aufgetreten! Die Adress-Nummer ist bereits vergeben.");
                    }              
                }
     
                return Json(new[] { adressen }.ToDataSourceResult(request, ModelState));
            }
     
            [AcceptVerbs(HttpVerbs.Post)]
            public ActionResult Delete([DataSourceRequest] DataSourceRequest request, Adressen adressen)
            {
                Adressen Adressen = null;
     
                if (ModelState.IsValid)
                {
                    Adressen = db.Adressen.Find(adressen.Eadr);
                    db.Adressen.Remove(Adressen);
                    db.SaveChanges();
                }
     
                return Json(new[] { adressen }.ToDataSourceResult(request, ModelState));
            }
     
            [AcceptVerbs(HttpVerbs.Post)]
            public ActionResult Edit([DataSourceRequest] DataSourceRequest request, Adressen adressen)
            {
                if (adressen != null && ModelState.IsValid)
                {
                    db.Entry(adressen).State = EntityState.Modified;
                    db.Entry(adressen.BaLand).State = EntityState.Unchanged;
     
                    try
                    {
                        db.SaveChanges();
                    }
                    catch (InvalidOperationException ex)
                    {
                        ModelState.AddModelError(string.Empty, "Es ist ein Fehler aufgetreten! Der Datensatz wurde nicht gespeichert");
                    }
                    catch (DbEntityValidationException ex)
                    {
                        ModelState.AddModelError(string.Empty, "Es ist ein Fehler aufgetreten! Der Datensatz wurde nicht gespeichert");
                    }
                    catch (DbUpdateException ex)
                    {
                        ModelState.AddModelError(string.Empty, "Es ist ein Fehler aufgetreten! Der Datensatz wurde nicht gespeichert");
                    }   
                }
                 
                return Json(new[] { adressen }.ToDataSourceResult(request, ModelState));
            }    
        }
    Model for Adress
    public partial class Adressen
        {
            public int Eadr { get; set; }
            public string Nama { get; set; }
            public string Namb { get; set; }
            public string Namc { get; set; }
            public string Namd { get; set; }
            public string Name { get; set; }
            public string Namf { get; set; }
            public string Pstc { get; set; }
            public string Ccty { get; set; }
     
            public virtual BaLand BaLand { get; set; }
        }
    Model for Countries
    public partial class BaLand
    {
        public string Ccty { get; set; }
        public string Dsca { get; set; }
        public string Ictc { get; set; }
        public Nullable<short> Meec { get; set; }
        public string Tfcd { get; set; }
    }
  2. Vladimir Iliev
    Admin
    Vladimir Iliev avatar
    2192 posts

    Posted 16 Oct 2013 Link to this post

    Hi Helga,

     
    Basically sorting / filtering / grouping of columns that are bound to a complex property from the model is not supported out-of-the-box as the Grid didn't have the information about which of the nested fields should be used for these operations. In current scenario I would suggest to flatter your model and use ForeignKeyColumn to match values from the column to their texts. Another option is to bind the column directly to the nested property as demonstrated below:

    columns.Bound(p => p.Category.CategoryName);

    Kind Regards,
    Vladimir Iliev
    Telerik
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  3. Answer
    Helga
    Helga avatar
    3 posts
    Member since:
    Jan 2013

    Posted 21 Oct 2013 Link to this post

    Hello Vladimir,
    thanks for your Help!
    I've bound the Column directly to the nested Property an Sorting/Filtering etc is working.
    columns.Bound(p => p.BaLand.Dsca).Title("Bezeichnung").ClientTemplate(" #= BaLand ? BaLand.Dsca : '' # ");
    But now, my Custom Editor (Shared/EditorTemplates/BaLand.cshtml) isn't working. How should I name the EditorTemplate File?
    @(Html.Kendo().DropDownList()
        .Name("BaLand")
        .BindTo((System.Collections.IEnumerable)TempData["Land"])
        .DataTextField("Dsca")
        .DataValueField("Ccty")
        .OptionLabel("Bitte wählen")
        .Events(e => e
            .Change("baland_change")
        )
    )
    Thanks for help
  4. Helga
    Helga avatar
    3 posts
    Member since:
    Jan 2013

    Posted 21 Oct 2013 Link to this post

    Just found the solution. The UIHint: [UIHint("Dsca")].
    Now, all is working perfect :)

    Thanks
Back to Top