Initial values serialization problem using wrapper

5 posts, 0 answers
  1. Ori
    Ori avatar
    10 posts
    Member since:
    Feb 2015

    Posted 13 Mar 2015 Link to this post

    Hi,
    I've come accross a very strange behavior of multiselect wrapper in a certain situation. I'm either not using the control properly or maybe it could be a wrapper bug.
    The model contains two properties:
     - ItemIds (to be Posted back on submit)
     - Items (contains complete objects, with all properties for presenting like Code, Name and Id)

    The initially preselected Model.Items are directly put into the code on the server, rest of items user can select is loaded via AJAX.

    @(Html.Kendo().MultiSelectFor(x => x.ItemIds)
            .DataValueField("Id")
            .TagTemplate("#:data.Code# - #:data.Name#")
            .ItemTemplate("#:data.Code# - #:data.Name#")
            .AutoBind(false)
            .Value(Model.Items)
            .DataSource(d => d.Read(r => r.Action("GetItems", "ItemService").Data("getAdditionalData"))
            .ServerFiltering(true))
    )

    So, when the page is loaded, the MultiSelect contains some initially preselected items (properly serialized as objects in the javascript code), we can add some more, post them back. So far so good.

    But - when we add some validation (no matter which control contains invalid data) and the ModelState in the controller becomes invalid, the javascript serialization of the .Value(Model.Items) doesn't serialize all object properties (like Code, Name and Id) but only the Id property. So there are no initially preselected items in the multiselect.
    I'm 100% sure the Model.Items contains all the information in both situations - no matter if the model state is valid and invalid. 

    I've also a workaround for this problem. Do not use the wrapper - use the javascript and serialize the Model.Items manualy like this:

    01.$(selector).kendoMultiSelect({
    02.                "dataSource": {
    03.                    "transport": {
    04.                        "read": {
    05.                            "url": "/ItemService/GetItems",
    06.                            "data": getAdditionalData
    07.                        },
    08.                        "prefix": ""
    09.                    },
    10.                    "serverFiltering": true,
    11.                    "filter": [],
    12.                    "schema": { "errors": "Errors" }
    13.                },
    14.                "itemTemplate": "#:data.Code# - #:data.Name#",
    15.                "tagTemplate": "#:data.Code# - #:data.Name#",
    16.                "autoBind": false,
    17.                "dataValueField": "Id",
    18.                "value": @Html.Raw(Json.Encode(Model.Items))
    19.            });

    But this workaround complicates other things and I really would prefer to use the wrapper instead of this. 

    Thanks,

    Ori
  2. Daniel
    Admin
    Daniel avatar
    2118 posts

    Posted 17 Mar 2015 Link to this post

    Hello,

    As all other HTML helpers, the multiselect will set the value from the ModelState if available which will be the posted Id value. You could remove the ModelState entry for the multiselect property in the post action:
    ModelState.Remove("ItemIds");
    so that the value is populated from the model in both cases.

    Regards,
    Daniel
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
  3. Kendo UI is VS 2017 Ready
  4. Ori
    Ori avatar
    10 posts
    Member since:
    Feb 2015

    Posted 26 Mar 2015 in reply to Daniel Link to this post

    Hi, 
    I've tried this advice, it works - but, there are two problems that make it unusable in the real world:

    1) A fatal one - if I remove an item from ModelState like this, I also remove validation errors, so if "ItemIds" MultiSelect was posted with invalid data, the validation message never gets it to the CSHTML control @(Html.ValidationMessageFor(x => x.ItemIds))

    2) How can I use this advice for all Kendo widgets that have ajax datasource? It would not be systematic to always call ModelState.Remove for certain Model properties in HttpPost Controller Actions. 
  5. Daniel
    Admin
    Daniel avatar
    2118 posts

    Posted 30 Mar 2015 Link to this post

    Hello again,

    You could clear just the value if validation is used for the property:
    ModelState["ItemIds"].Value = null;
    As for your other question - you could create a custom helper or an extension method for the widget that does this automatically e.g.
    public static class KendoExtensions
    {
        public static MultiSelectBuilder ModelValue(this MultiSelectBuilder builder, IEnumerable value)
        {
            builder.Value(value);
            var component = builder.ToComponent();
            var modelEntry = component.ViewData.ModelState[component.Name];
            if (modelEntry != null)
            {
                modelEntry.Value = null;
            }
            return builder;
        }
    }
    Html.Kendo().MultiSelectFor(x => x.ItemIds)
        .ModelValue(Model.Items)


    Regards,
    Daniel
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
  6. Ori
    Ori avatar
    10 posts
    Member since:
    Feb 2015

    Posted 30 Mar 2015 in reply to Daniel Link to this post

    That's awesome solution! 

    Thank you
    Ori
Back to Top
Kendo UI is VS 2017 Ready